【问题标题】:Updating child props from parent state in ReactJS在 ReactJS 中从父状态更新子道具
【发布时间】:2017-01-24 20:22:54
【问题描述】:

我正在尝试了解如何构建具有不同“页面”或“视图”的 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 回调时,组件永远不会收到更新的食谱数组。

我怎样才能根据应用中的更新状态来更新它的道具?

还是我以错误的方式处理整个事情?

【问题讨论】:

  • 我假设正在发生的事情是因为“Home”组件是在构造函数中定义的,并且您将其食谱设置为那里的数组,当您更新食谱数组时,您不是将元素推送到现有数组上,而是为变量设置一个新数组,因此组件永远不会使用新数据更新。

标签: reactjs


【解决方案1】:

我认为您的方法并不是真正的反应式,并且您至少有几个可以改进的概念。

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

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

如果在状态中存储应该在组件中渲染的内容,您可能应该使用在构造函数中初始化的状态中的简单标志来补充 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>

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

        我同意@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];
            }
         }
        

        【讨论】:

          猜你喜欢
          • 2016-09-18
          • 2016-11-03
          • 2016-10-02
          • 1970-01-01
          • 1970-01-01
          • 2018-07-08
          • 2020-09-24
          • 1970-01-01
          • 2015-12-02
          相关资源
          最近更新 更多