简体   繁体   English

在ReactJS中从父状态更新子道具

[英]Updating child props from parent state in ReactJS

I'm trying to understand how I can structure a ReactJS app with different "pages" or "views". 我试图了解如何构造具有不同“页面”或“视图”的ReactJS应用程序。

I have the following component as my base app and I'm using a currentState property in the React state to switch between which Components are active in the view. 我将以下组件作为基本应用程序,并且在React状态下使用currentState属性在视图中处于活动状态的组件之间进行切换。

class App extends React.Component {

    constructor(props) {
        super(props);
        this.state = {currentState: 'Loading', recipes: []};
        this.appStates = {
            'Loading': <Loading/>,
            'Home': <RecipeList recipes={this.state.recipes}/>
        }
    }

    dataLoaded(data) {
        this.setState({
            recipes: data,
            currentState: 'Home'
        });
    }

    componentDidMount() {

        // AJAX Code that retrieves recipes from server and then calls dataLoaded
    }

    render() {
        return this.appStates[this.state.currentState];
    }
}

Which does the job, but the component never receives the updated recipes array when the dataLoaded callback is fired. 哪个可以完成工作,但是在触发dataLoaded回调时,组件永远不会收到更新的配方数组。

How can I cause the to update its props based on the updated state in the App? 我该如何根据App中的更新状态来更新道具?

Or am I approaching this whole thing the wrong way? 还是我以错误的方式来处理整件事?

I think that your aproach isn't really react-like, and you have at least a couple of concepts that can be improved. 我认为您的方法并不是真的很像反应,并且您至少有两个可以改进的概念。

First of all, I would definitely use react-router to achieve any complex navigation between pages/Components in React.js. 首先,我肯定会使用react-router在React.js中的页面/组件之间实现任何复杂的导航。 Implementing it yourself is more complicated and error-prone. 自己实施更复杂且容易出错。 react-router will allow you to assign Components to different routes easily. react-router允许您轻松地将组件分配给不同的路由。

Second, I think that you should almost never store things in the context this directly. 其次,我认为你应该几乎从不存储在上下文中的东西this直接。 Basically because it leads to errors like yours here: not realizing that appStates isn't changing at all. 基本上是因为它会导致像您这样的错误:根本没有意识到appStates根本没有改变。 React's state is a great tool (which must sometimes be replaced/complemented with others like Redux) to store your application's state. React的状态是一个很棒的工具(有时必须用Redux等其他工具替换/补充)来存储应用程序的状态。

In the case of storing in the state what should be rendered in the Component, you should probably complement the react-router functionality with simple flags in the state initializated in the constructor that allow you to know what should you return in the render function. 在以状态形式存储应该在Component中呈现的内容的情况下,您可能应该在构造函数中初始化的状态下使用简单标志来补充react-router功能,以使您知道应该在render函数中返回什么。

Here is an example that shows how can you tell a component to change its view dynamically between loading and loaded by using just React's state. 这是一个示例,显示了如何告诉组件仅使用React的状态在加载和加载之间动态更改其视图。 Of course, you could recreate a very similar behaviour making an AJAX call in componentDidMount and changing the state to stop loading when it's done instead of using a button. 当然,您可以重新创建一个非常相似的行为,即在componentDidMount中进行AJAX调用,并更改状态以在完成后停止加载,而不是使用按钮。

 class App extends React.Component { constructor(props) { super(props); this.state = {loading: true}; this.stopLoading = this.stopLoading.bind(this); } stopLoading() { this.setState({ loading: false, }); } render() { let view=<div><h1>loading</h1><button onClick={this.stopLoading}>FINISH</button></div>; if(!this.state.loading){ view=<h1>loaded</h1>; } return <div>{view}</div>; } } ReactDOM.render( <App />, document.getElementById('container') ); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> <div id="container"></div> 

Your constructor method is only executed when the component mounts, at which point recipes is empty, and passes that empty array to appStates. 您的构造方法仅在组件安装时执行,此时配方为空,并将该空数组传递给appStates。 Essentially, appStates never changes. 本质上,appStates永远不会改变。

What I would recommend doing is pushing all the component code in the constructor to inside the render function. 我建议做的是将构造函数中的所有组件代码推送到render函数内部。 The beauty of react is that you can completely re-render everything at very little cost. 反应的好处在于您可以以很少的成本完全重新渲染所有内容。 React will do the hard work of comparing the difference in DOMs and only re-render the minimal differences. React将进行比较DOM差异的艰苦工作,并且仅重新呈现最小差异。

I agree with @Ezra Chang. 我同意@Ezra Chang。 I think the code could be adjusted making use of just the state and the javascript spread function to pass the App props to the child RecipeList: 我认为可以仅使用状态和javascript传播函数来调整代码,以将App道具传递给子RecipeList:

class App extends React.Component {

   constructor(props) {
      super(props);
      this.state = {currentState: 'Loading', recipes: [],'Loading': <Loading/>,
        'Home': <RecipeList recipes={this.state.recipes} {...this.props}/>};
   }

   //I assume you want to pass the props of this App component and the data from the back-end as props to RecipeList. 
   dataLoaded = (data) => {
       this.setState({
          recipes: data,
          currentState: 'Home',
          'Loading': <Loading/>,
          'Home': <RecipeList recipes={data} {...this.props}/>
       });
    }

    componentDidMount() {
       // AJAX Code that retrieves recipes from server and then calls dataLoaded
    }

    render() {
       return this.state[this.state.currentState];
    }
 }

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

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