当子状态实际上引用来自父的道具时,为什么父道具不等于子状态

Why aren't parent Props Equal to Child state when Child state actually reference props from parent

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

我尝试了什么:

  1. State Updates May Be Asynchronous,我已经使用回调而不是返回对象来解决这个问题。
  2. ,但是我用的prop是字符串

我正在使用 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'));

这里是codepen PEN - 注意redered元素应该根据状态隐藏(状态取决于父级的道具)

如果从子进程中删除不需要的状态定义,并仅使用从父进程传递的 props,我相信子进程的行为是有意义的。

如果你想在child中使用state,constructor设置是不够的,你需要在props变化时设置child state。

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

使用 componentWillReceiveProps,当 props 发生变化时调用。

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>
    }
}

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

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

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

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

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

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

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

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