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

时间:2018-05-30 04:50:08

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

我将来自Parent组件的道具传递给Child的状态,但它们不同步。

我尝试了什么:

  1. State Updates May Be Asynchronous,我已经使用回调而不是返回对象来处理它。
  2. Objects are passed by reference,但我使用的道具是一个字符串。
  3. 我正在使用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元素(state依赖于来自parent的props)

    console shows my props and state are not equal

4 个答案:

答案 0 :(得分:2)

如果从孩子那里删除状态定义(不需要),并且只使用从父母传递的道具,我相信孩子的行为是有意义的。

如果你想在子节点中使用state,那么构造函数设置是不够的,你需要在props更改时设置子状态。

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

答案 1 :(得分:2)

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

答案 2 :(得分:1)

由于组件对构造函数中的状态更改一无所知,因此您的子状态不会随着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更改博客文章,包括异步呈现: https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html

答案 3 :(得分:1)

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

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

尝试编写这样的组件,我相信它应该有效:

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

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