简体   繁体   English

如何在嵌套的React组件中传递状态和处理程序

[英]How to pass down state and handlers in nested React components

I'm having an issue passing down handlers through my React components. 我在通过React组件传递处理程序时遇到问题。

I've tried following the instructions in the Lifting State Up section of the React docs. 我已经尝试按照React文档的Lifting State Up部分中的说明进行操作。

The idea is to have a Page with tabbed navigation, and each tab would render the display of some subpage. 想法是创建一个带有选项卡式导航的页面,每个选项卡将呈现某些子页面的显示。 I have a component Page.js for my overall page, and that's where I'm storing the activeTab state and where I think I should define the function that handles state change. 我的整个页面都有一个组件Page.js ,这是我存储activeTab状态的地方,我认为应该定义处理状态变化的功能。 I then pass down the activeTab state and the handler as props to the TabMenu.js component, which in turn passes it down to the TabItem.js components. 然后,我将activeTab状态和处理程序作为道具传递给TabMenu.js组件,然后依次将其传递给TabItem.js组件。

The files: 文件:

Page.js Page.js

import React, { Component } from 'react';

import TabMenu from './TabMenu';
import FooPage from './FooPage';
import BarPage from './BarPage';

class Page extends Component {

    constructor(props) {
        super(props);
        this.state = {
            activeTab: 'foo'
        };

        this.setActiveTab = this.setActiveTab.bind(this);
    }

    getVisiblePage() {
        switch(this.state.activeTab) {
            case 'bar':
                return (
                    <FooPage />
                );
            case 'foo':
            default:
                return (
                    <BarPage />
                );
        }
    }

    setActiveTab(e, tab) {
        this.setState({
            activeTab: tab
        });
    }

    render() {
        var visiblePage = this.getVisiblePage();

        return (
            <section>
                <TabMenu
                    activeTab={ this.state.activeTab }
                    changeTabHandler={ this.setActiveTab }
                />
                { visiblePage }
            </section>
        );
    }
}

export default Page;

TabMenu.js: TabMenu.js:

import React, { PropTypes } from 'react';

import TabItem from './TabItem';

const TabMenu = ({ activeTab, changeTabHandler }) => {

    const tabs = [
        {
            key: 'foo',
            text: 'Foo Page',
        },
        {
            key: 'bar',
            text: 'Bar Page'
        },
    ];

    const tabItems = tabs.map((item) => (
        <TabItem
            key={ item.key } 
            item={ item }
            isActive={ item.key === activeTab }
            changeTabHandler={ changeTabHandler }
        />
    ));

    return (
        <nav id="TabMenu">
            <ul className="tab-items">
                { tabItems }
            </ul>
        </nav>
    );
};

TabMenu.displayName = 'TabMenu';

TabMenu.propTypes = {
    activeTab: PropTypes.string,
    changeTabHandler: PropTypes.func,
};

export default TabMenu;

TabItem.js TabItem.js

import React, { PropTypes } from 'react';

const TabItem = ({ item, changeTabHandler }) => {
    return (
        <li onClick={ changeTabHandler(item.key) }>
            { item.text }
        </li>
    );
};

TabItem.displayName = 'TabItem';

TabItem.propTypes = {
    item: PropTypes.object,
    changeTabHandler: PropTypes.func,
};

export default TabItem;

The end results is that my console overflows with 1000s of copies of the following error: 最终结果是我的控制台溢出了以下错误的1000份副本:

warning.js:36 Warning: setState(...): Cannot update during an existing state transition (such as within render or another component's constructor). warning.js:36警告:setState(...):在现有状态转换期间(例如在render或其他组件的构造函数中)无法更新。 Render methods should be a pure function of props and state; 渲染方法应该纯粹是道具和状态的函数; constructor side-effects are an anti-pattern, but can be moved to componentWillMount . 构造函数的副作用是反模式,但是可以将其移至componentWillMount

What am I doing wrong? 我究竟做错了什么?

That infinite loop is because you have something inside the parent component's render function, which invoke setState or trigger some update to another component which affects the state of the origin or parent component which then will call render again. 该无限循环是因为您在父组件的render函数中包含一些东西,该函数调用setState或触发对另一个组件的更新,这会影响原始或父组件的状态,然后再次调用render。

in your case, it's because in TabItem.js, 就您而言,这是因为在TabItem.js中,

<li onClick={ changeTabHandler(item.key) }>
            { item.text }
        </li>

actually invoke changeTabHandler immediately which will do setState in Page, and then TabItem will render and call changeTabHandler again 实际上立即调用changeTabHandler ,它将在Page中执行setState,然后TabItem将呈现并再次调用changeTabHandler

change it to 更改为

<li onClick={() => changeTabHandler(item.key) }>
            { item.text }
        </li>

Your changeTabHandler() is getting invoked immediately, once for each <li> you are rendering. 您的changeTabHandler()立即被调用,对您渲染的每个<li>一次。 Change this: 更改此:

<li onClick={ changeTabHandler(item.key) }>

to this: 对此:

<li onClick={ () => changeTabHandler(item.key) }>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM