how to update both parent and child state before render without extra renders in React 15

Viewed 22

If I use setState in the child and place a callback in the parent to update the parent state that propagates to child props, then I end up with two render calls.

One for the update to the child state, and one for the prop changing. I can manually use shouldComponentUpdate to ignore the prop change if I want, but the render won't be ready until the state updates.

I know all this can be done easily in react 16-18, but migrating is not simple at the moment.

I am wondering if the solution is to make the child state the source of truth. I can solve all my problems this way, but I thought in react you typically made the parent the source of truth.

Parent Component Child Component

ChildComponent

function = () => {
  this.setState ( {updatedStateProperty}, callback())
}

ParentComponent

callback = () => {
    this.setState ( {propSentToChild})
}

What happens is the child component changes state, then render occurs, then the callback occurs, prompting another render.

I want to either A. change child state, then have the callback called before render or B. update child state, then ignore the parents passed props

I can do B, but I'm unsure whether it is proper form to basically make the child's version of the shared state the source of truth

1 Answers

I think you're kind of close. What you really want to do is pass the state to the parent, handle setting the state there, and let the new state trickle down to your child component via props. This is a fairly common pattern for react.

class Parent extends React.Component {
  constructor() {
    this.state = { foo: "bar", bing: "baz" }
  }
  stateUpdater(newState) {
    this.setState({ ...this.state, ...newState });
  }
  render() {
    return <Child 
      prop1={this.state.foo} 
      prop2={this.state.baz}
      stateUpdater={this.stateUpdater} 
    />
  }
}

class Child extends React.Component {
  handleClick = () => {
    this.props.stateUpdater({ foo: 'bazaar' });
  }
  render() {
    return <div>
      The foo is {this.props.foo} and the baz is {this.props.baz}.
      <button onClick={this.handleClick}>Click Me!</button>
    </div>
  }
}
Related