【问题标题】:Why aren't parent Props Equal to Child state when Child state actually reference props from parent当子状态实际上从父级引用道具时,为什么父级道具不等于子状态
【发布时间】:2018-11-08 19:56:42
【问题描述】:

我将 props 从 Parent 组件传递到 Child 的状态,但它们不同步。

我尝试了什么:

  1. State Updates May Be Asynchronous,我已经使用回调而不是返回对象来解决这个问题。
  2. Objects are passed by reference,但是我使用的道具是一个字符串。

我正在使用 React 16 和 es6 语法

class Parent extends React.Component {
  state = {
   isHidden: false
  }
  render() {
   console.log('PROPS from PARENT', this.state.isHidden)
   return <div>
     <Child isOpen={this.state.isHidden} />
     <button onClick={this.toggleModal}>Toggle Modal</button>
    </div>
   }
  toggleModal = () => this.setState(state => ({isHidden: !state.isHidden}))
 }

class Child extends React.Component {
  state = {
   isHidden: this.props.isOpen
  }
  render() {
    console.log('STATE of CHILD:',this.state.isHidden)
    return <p hidden={this.state.isHidden}>Hidden:{this.state.isHidden}</p>
  }
}
ReactDOM.render(<Parent/>, document.getElementById('app'));

这里是一个代码笔PEN - 注意重新渲染的元素应该根据状态隐藏(状态取决于父级的道具)

【问题讨论】:

  • 请注意,设置直接从 props 派生的状态通常不是正确的方法,因为您始终可以直接从 props 使用值,只有在 props 需要更改的情况下才应该这样做仅在特定动作后从道具中获得
  • 这正是我的代码所做的,将状态设置为道具,然后根据特定操作设置状态@ShubhamKhatri 谢谢。
  • 通过一个特定的动作,我的意思是触发从子级到父级的更新而不是相反的动作。例如,您可能希望根据 props 预填充表单数据,然后编辑这些数据并在提交操作上将数据发送回父级。
  • 我没有触发孩子的动作吗?我不明白

标签: reactjs ecmascript-6 react-props react-state-management


【解决方案1】:

虽然其他答案会让代码工作,但实际上有一个更优雅的解决方案:)

您的子组件不需要任何状态,因为状态由父组件管理(它管理isHidden 属性并将其传递给子组件)。所以子组件应该只关心 props。

尝试像这样编写组件,我相信它应该可以工作:

class Child extends React.Component {
  render() {
    return <p hidden={this.props.isHidden}>Hidden:{this.props.isHidden}</p>
  }
}

在 React 团队工作的 Dan Abramov 发布了关于这个问题的推文 - 本质上是说你应该认真考虑在组件中使用状态之前是否可以只使用 props https://twitter.com/dan_abramov/status/979520339968516097?lang=en

【讨论】:

    【解决方案2】:

    你的孩子的状态不会随着道具的改变而改变,因为组件对你的构造函数中的状态变化一无所知。当您依赖道具来构建本地状态时,这是一个常见的陷阱。您可以使用 @Nishant Dixit 的答案中所示的 componentWillReceiveProps 。但是,从 React 16.3 开始,我们为此提供了 getDerivedStateFromProps 函数(生命周期方法)。

    static getDerivedStateFromProps( props, state) {
        if( props.isOpen === state.isHidden) {
          return null;
        }
        return {
          isHidden: props.isOpen,
        }
      }
    

    在这里,我们正在比较我们的 prop 和 state,如果有变化,我们将返回所需的 state。无需使用 this.setState。

    包括异步渲染的相关 API 更改博客文章: https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html

    【讨论】:

    • 我回答了我自己并删除了它,...您介意编辑您的内容以包含指向该 API 的链接@devserkan,也非常感谢您的解释!
    • 您的意思是:reactjs.org/blog/2018/03/27/update-on-async-rendering.html 或仅提及签名的官方文档?
    • idk,随便你觉得有帮助
    • 好的,我已经添加了。
    【解决方案3】:

    如果你把不需要的 state 定义从 child 中移除,只使用从 parent 传递过来的 props,我相信 child 的行为会有意义。

    如果要在child中使用state,构造函数设置是不够的,需要在props变化时设置child state。

    Console.log 是异步的,所以你不能在这里依赖它。

    【讨论】:

    • you need the set the child state when props changes... 怎么样?
    • 谢谢@rahamin,你帮我指出了正确的方向,我发现 react 16s 新 API `static getDerivedStateFromProps`
    • 刚刚看到你的问题...我假设你找到了答案。
    【解决方案4】:

    使用componentWillReceivePropsprops 发生更改时调用。

    class Child extends React.Component {
        state = {
            isHidden: this.props.isOpen
        }
        componentWillReceiveProps(props) {
    
            if (props.isOpen != this.state.isHidden)
                this.setState({
                    isHidden: props.isOpen
                })
    
        }
        render() {
            console.log('STATE of CHILD:', this.state.isHidden)
            return <p hidden = {
                this.state.isHidden
            } > Hidden: {
                this.state.isHidden
            } < /p>
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2016-11-03
      • 1970-01-01
      • 2020-09-24
      • 1970-01-01
      • 2016-05-13
      • 2014-10-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多