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

时间:2017-01-24 20:22:54

标签: reactjs

我试图了解如何使用不同的"页面来构建ReactJS应用程序"或"观点"。

我有以下组件作为我的基本应用程序,并且我在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];
    }
}

这是什么工作,但是当触发dataLoaded回调时,组件永远不会收到更新的recipes数组。

如何根据应用程序中的更新状态更新其道具?

或者我是以错误的方式接近这一切?

4 个答案:

答案 0 :(得分:2)

我认为你的方法并没有真正的反应,你至少有几个可以改进的概念。

首先,我肯定会使用react-router来实现React.js中页面/组件之间的任何复杂导航。自己实现它更复杂,更容易出错。 react-router将允许您轻松地将组件分配到不同的路由。

其次,我认为您几乎不应该直接在上下文this中存储内容。基本上是因为它会导致像你这样的错误:没有意识到appStates根本没有改变。 React的状态是一个很好的工具(有时必须用Redux等其他替换/补充)来存储应用程序的状态。

如果在状态中存储应该在Component中呈现的内容,则应该使用构造函数中初始化状态中的简单标志来补充react-router功能,以便您知道在渲染中应该返回什么功能

这是一个示例,显示如何通过仅使用React的状态来告诉组件在加载和加载之间动态更改其视图。当然,您可以重新创建一个非常相似的行为,在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>

答案 1 :(得分:1)

构造函数方法仅在组件安装时执行,此时配方为空,并将该空数组传递给appStates。从本质上讲,appStates永远不会改变。

答案 2 :(得分:0)

我建议做的是将构造函数中的所有组件代码推送到render函数中。反应的美妙之处在于,您可以以极低的成本完全重新渲染所有内容。 React将努力比较DOM中的差异,只重新渲染最小差异。

答案 3 :(得分:0)

我同意@Ezra Chang。我认为代码可以调整,只使用状态和javascript spread function将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];
    }
 }