Ad

How To Update (re-render) The Child Components In React When The Parent's State Change?

Okay, I already know one way to do this. However, I am asking this in case I am reinventing the wheel since I am very new to React. I was under the impression that if a parent component passes her state to the child components via props than upon updating the parent's state, the child will re-render if needed. But this does not seem to be the case. I set up this example,

class Child extends Component {
  constructor(props) {
    super(props);
    this.state = {
      number: props.number,
    };
  }

  updateNumber(n) {
    this.setState({number: n});
  }

  render() {
    return (<h1>{this.state.number}</h1>);
  }
}

class Parent extends Component {

  constructor(props) {
    super(props);
    this.state = {
      number: -1,
    };
    this.child = React.createRef();
    setInterval(this.updateState.bind(this), 1000);
  }

  updateState() {
    console.log(this.state);
    this.setState({
      number: Math.floor((Math.random() * 10) + 1),
    });
    // this.child.current.updateNumber(this.state.number);
  }

  render() {
    return (
      <div>
        <Child ref={this.child} number={this.state.number}/>
      </div>
    );
  }
}

In this example, unless I explicitly define a reference and use it to call the child's update function (the commented part), child is not re-rendered each time the parent's state is updated. So is that it? Are you suppose to manually update the state of your children (heh) or should they automatically update (and thus re-render) if their parent's state is passed to them as props.

Ad

Answer

It is because your Child component is using its own state as well. Always ask yourself if state is necessary, its a common mistake for React beginner.

Hope you can understand it more by looking at this example. Instead of calling setInterval in your constructor function, I will recommend you to call it in componentDidMount and to clearInterval in your componentWillUnmount.

// Since you are not using state, you can use functional component for your Child component
const Child = ({ number }) => <h1>{number}</h1>;

class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.timer = null;
    this.state = { number: 0 };
  }

  componentDidMount() {
    // setInterval after component did mount
    this.timer = setInterval(this.incrementNumber, 1000);
  }

  componentWillUnmount() {
    // clearInterval when component is going to unmount
    if (this.timer) {
      clearInterval(this.timer);
    }
  }

  incrementNumber = () => {
    // setState function callback to ensure state received will be latest state
    this.setState(prevState => ({ number: prevState.number + 1 }));
  }

  render() {
    const { number } = this.state;
    return (
      <div>
        <Child number={number} />
      </div>
    );
  }
}
Ad
source: stackoverflow.com
Ad