Rerender React child component with a complex/nested state update

3k Views Asked by At

Below is a sample version of my actual code.

// parent component
this.state = {
  ...,
  dummies: [
    {id: 1, name: "nothing"},
    {id: 2, name: "nothing"},
    {id: 3, name: "nothing"}
  ],
  ...
};

render(){
  return <ChildComponent dummies={this.state.dummies} />;
};

// ChildComponent
this.state = {
  ...,
  dummies: this.props.dummies
};
...
{
  this.state.dummies.map((eachDummy) => {
    return <GrandChild id={eachDummy.id} dummy={eachDummy} />
  });
}

After some interactions, I'm updating dummies in my parent's state as below

this.setState({
  ...this.state,
  dummies: [
    {id: 1, name: "something"}, // observe change in name property
    {id: 2, name: "nothing"},
    {id: 3, name: "nothing"}
  ]
})

Here comes the real problem. How do I get my Child and GrandChild components to render when a small change in the dummiess' name attribute happens? I think the shallow comparison of React is not able to identify the change, but I need Child and GrandChild to rerender and update UI. How can I achieve this? (Please note, I cannot avoid array of objects in state)

1

There are 1 best solutions below

1
On BEST ANSWER

For the grandchild component to re-render when you update the parent component state, it must ultimately use the parent's state in its render method, by way of props. In the render method of your child component, you are passing to the grandchild components 'dummies' from the child's state, not its props.

The following is a working example of what you described:

class Parent extends Component {
  constructor() {
    super();
    this.state = {
      dummies: [
        {id: 1, name: "nothing"},
        {id: 2, name: "nothing"},
        {id: 3, name: "nothing"}
      ]
    }
  }

  render() {
    return <div>
      <button onClick={() =>
        this.setState({
          dummies: [
            {id: 1, name: "nothing"},
            {id: 2, name: "nothing"},
            {id: 3, name: "something"}
          ]
        })
      }>
        Update state
      </button>
      <Child dummies={this.state.dummies} />
    </div>
  }
}

class Child extends Component {
  render() {
    return this.props.dummies.map(dummy => <GrandChild name={dummy.name} />);
  }
}

class GrandChild extends Component {
  render() {
    return <p>{this.props.name}</p>;
  }
}

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