2017-01-24 104 views
0

我在尝试了解如何使用不同的“页面”或“视图”构建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回调被触发时,组件从不接收更新的配方数组。

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

或者我以错误的方式接近这件事?

+0

我认为正在发生的事情是因为“家”组件在构造函数中被定义,并且您将它的配方设置到数组中,当您更新配方数组时,您不会将元素推送到现有数组上,而是将新数组设置为该变量,因此组件从不更新为新数据。 – dule

回答

0

我推荐做的是将构造函数中的所有组件代码推送到render函数中。反应的美妙之处在于你可以以很低的成本完全重新渲染所有东西。 React将做比较DOM差异的艰巨工作,并只重新渲染最小差异。

1

您的构造函数方法仅在组件挂载时执行,此时食谱为空,并将该空数组传递给appStates。实质上,appState从不改变。

2

我认为你的见解并不是真正的反应,而且你至少有一些可以改进的概念。

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

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

在存储应该在组件中呈现的内容的情况下,您应该在构造函数中初始化的状态下用简单的标志补充反应路由器的功能,以便让您知道应该返回哪些内容渲染功能。

下面是一个示例,显示如何通过使用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>

0

我@Ezra昌同意。我觉得代码可以调整,只需使用状态和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]; 
    } 
}