在与对象作出反应的孩子之间共享状态

时间:2018-01-20 10:09:38

标签: javascript reactjs state

当我尝试更新其中一个孩子的所有子状态时,我遇到了一些问题,这是我的代码示例。我们的想法是从其中一个组件中自动更新所有组件。

我有新的反应,我只使用了一个星期,所以这可能是一个误解。

https://codesandbox.io/s/430qwoo94

import React from 'react';
import { render } from 'react-dom';
import Hello from './Hello';

class Parent extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      filedStr: 'some text',
      fieldObj: {
        field1: true,
        field2: true
      }
    }
      }

  updObj = (which, val) => {
    this.setState(prevState => ({
      fieldObj: {
        ...prevState.fieldObj,
        [which]: val,
      },
    }));
  };

  render() {
    return (
      <div>
        <h2>Parent</h2>
        Value in Parent Component State: {this.state.fieldObj.field1 ? 1 : 0} : {this.state.fieldObj.field2 ? 1 : 0}
        <br />
        <Child obj={this.state.fieldObj} onUpdate={this.updObj} />
        <br />
        <Child obj={this.state.fieldObj} onUpdate={this.updObj} />
        <br />
        <Child obj={this.state.fieldObj} onUpdate={this.updObj} />
      </div>
    )
  }
}

class Child extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      obj: props.obj
    }
      }

  update = (which) => {
    this.props.onUpdate(which, !this.state.obj[which]);
    this.setState(prevState => ({
      obj: {
        ...prevState.obj,
        [which]: !prevState.obj[which],
      },
    }));
  };

  render() {
    return (
      <div>
        <h4>Child</h4>
        Value in Child State: {this.state.obj.field1 ? 1 : 0} : {this.state.obj.field2 ? 1 : 0}<br />
        <button type="button" onClick={(e) => { this.update('field1') }}>field1</button>
        <button type="button" onClick={(e) => { this.update('field2') }}>field2</button>
      </div>
    )
  }
}

render(<Parent />, document.getElementById('root'));

2 个答案:

答案 0 :(得分:1)

当所有子组件值都可以直接从道具派生时,你不需要在子项中创建一个状态,这是一个道具的副本并维护它,你需要做的是直接修改父状态

import React from 'react';
import { render } from 'react-dom';
import Hello from './Hello';

class Parent extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      filedStr: 'some text',
      fieldObj: {
        field1: true,
        field2: true
      }
    }
  }

  updObj = (which, val) => {
    this.setState(prevState => ({
      fieldObj: {
        ...prevState.fieldObj,
        [which]: val,
      },
    }));
  };

  render() {
    return (
      <div>
        <h2>Parent</h2>
        Value in Parent Component State: {this.state.fieldObj.field1 ? 1 : 0} : {this.state.fieldObj.field2 ? 1 : 0}
        <br />
        <Child obj={this.state.fieldObj} onUpdate={this.updObj} />
        <br />
        <Child obj={this.state.fieldObj} onUpdate={this.updObj} />
        <br />
        <Child obj={this.state.fieldObj} onUpdate={this.updObj} />
      </div>
    )
  }
}

class Child extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      obj: props.obj
    }
  }

  update = (which) => {
    this.props.onUpdate(which, !this.props.obj[which]);
  };

  render() {
    return (
      <div>
        <h4>Child</h4>
        Value in Child State: {this.props.obj.field1 ? 1 : 0} : {this.props.obj.field2 ? 1 : 0}<br />
        <button type="button" onClick={(e) => { this.update('field1') }}>field1</button>
        <button type="button" onClick={(e) => { this.update('field2') }}>field2</button>
      </div>
    )
  }
}

render(<Parent />, document.getElementById('root'));

<强> CodeSandbox

但是,如果您想知道为什么您的处理方式不能按预期工作,那是因为您没有根据父级中的状态更新更新子组件的状态,您只需将其设置为一次组件只在组件安装时调用一次,你需要的是实现componentWillReceiveProps生命周期函数

答案 1 :(得分:0)

在此,我已更新您的代码以满足您的需求 - https://codesandbox.io/s/llnzm2y95z

您对孩子重新渲染的假设是错误的。当子进行重新渲染时,构造函数方法不会被调用,换句话说,构造函数只被调用一次。要使用下一个道具并更改状态,您需要使用渲染和componentWillReceiveProps。请参阅react-component生命周期http://busypeoples.github.io/post/react-component-lifecycle/

问题在于您使用onClick={(e) => { this.update('field1') }}onClick={(e) => { this.update('field1') }}

更新了父级的状态

您更新了父级状态,并且此状态再次传递给该子级。但在孩子你没有使用这个新的道具。你&#39;反而使用状态,此状态仅在构造函数中更新,在收到新道具后未更新。 (因为构造函数只被调用一次)

处理新道具的一种方法是直接使用渲染中的道具,因为组件将会重新渲染,并且可以使用更新的道具。

另一种方法是,如果要使用状态,则更新componentWillReceiveProps中的状态。 (我还想指出,强烈建议不要在componentWillReceiveProps和componentDidMount中执行setState)。所以最好先使用第一步。

componentWillReceiveProps(newProps) {
 if(newProps !== this.props){
  this.setState({newStateObjects})
 }
}