2
votes

I would like to update all child components in an array using a prop passed down from the state of a parent component. A basic example is shown below. Each child component in the array is stateless and has a prop value which is determined by the state of the parent component. However, when the parent components state changes, the child components do not re-render with the change. How can I make the child components re-render when the parents state changes? Thanks!

import React from 'react';
import ReactDOM from 'react-dom';

class Child extends React.Component {

  render(){
    return (
      <p>
        <button onClick = {(e) => this.props.onClick(e)}>
        click me
        </button>
        {this.props.test}
      </p>
    )
};
}

class Parent extends React.Component{

  constructor(props){
    super(props);
    this.state = {msg: 'hello', child_array: []};
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick(e){
    e.preventDefault();
    const msg = this.state.msg == 'hello' ? 'bye' : 'hello';
    this.setState({msg: msg});
  }

  componentDidMount(){
    let store = [];

    for (var i = 0; i < 5; i++){
      store.push(<Child test = {this.state.msg} key = {i} onClick = {this.handleClick}/>);
    }
    this.setState({child_array: store});
  }

  render(){
    return(
      <div>
        {this.state.child_array}
      </div>
    )
  }
}

ReactDOM.render(<Parent />, document.getElementById('root'));
3
It won’t re render again because you are generating chil components in componentDidMount and this method gets called only once per the component after first render. So when your callback fires the child_array will be empty - Hemadri Dasari

3 Answers

0
votes

The problem is that you're rendering the child components (and thus baking in the value of this.state.msg) in the parent's componentDidMount() method. You need to render them in the parent's render() method instead.

0
votes

As mentioned in comments

It won’t re render again because you are generating chil components in componentDidMount and this method gets called only once per the component after first render. So when your callback fires the child_array will be empty

Instead what you can do is remove componentDidMount method code and do that in render as like below. In the below case it will render every time the onclick fires in child component

render(){
     const store = [];
     for (var i = 0; i < 5; i++){
        store.push(<Child test = {this.state.msg} key = {i} onClick = {this.handleClick}/>);
       }
       return(
            <div>
              {store}
            </div>
       )
0
votes

componentWillReceiveProps will work in your case, everytime you will get props child component will re-render.

 class Child extends React.Component {
 constructor(props) {
  super(props);
  let initialData = (
  <p>
    <button onClick = {(e) => self.props.onClick(e)}>
    click me
    </button>
    {nextProps.test}
  </p>
 );
  this.state = {data: initialData };
 }
componentWillReceiveProps(nextProps) {
 let self = this;
 let updatedHtml = (
  <p>
    <button onClick = {(e) => self.props.onClick(e)}>
    click me
    </button>
    {nextProps.test}
  </p>
 );
 this.setState({data: updatedHtml})
}
render(){
 return (
  {data}
 )
 };
}