简体   繁体   中英

React component not rerendering when props changes

Here are my 2 React components - Parent and Child

class ParentComponent extends Component{

 render(){      
    /* consultations comes from redux store 
    and looks like { consultation_id:123, date:10/12/2013 } */
   return(
    _.map(this.props.consultations,(consultation)=>{

      return{
        <ChildComponent consultation={consultation} />
      }
    })
   );
  }
}

class ChildComponent extends Component{

  render(){
  return(
    <div>this.props.consultation.date</div> 
  );
  }
}

My problem is that I have certain actions that modify the consultations object. For eg: the props.consultation.date changes in the parent component, but the child component does not re render to show the latest consultation date.

However, I noticed that if I send each item in the consultations object to the child component like <ChildComponent date={this.props.consultation.date} /> it rerenders when the date changes!

Any idea why React does not re-render components when props sent as an object change?

I could always do with the work around but wondering if this is a bug or am I missing something?

You should definetly add the key prop with consultation_id to the child element. React can have problems rerendering elements without a key prop!

The solution is to change consultation={consultation} to consultation={...consultation}. I am still unsure why, but it works!

When you map over an array of items, you need to pass a unique key prop to each item. This signals to react which element is which.

...

_.map(this.props.consultations, consultation => {
  return (
    <ChildComponent 
      key={consultation.id} 
      consultation={consultation} 
    />
  )
})

The details you specified says that you change the date of same object~consultation in parent component and you parent component is getting the data as props. Now if you mutating the same consultation object it won't make component re-render.

consultation.date = /* some other date */;

it'll not re-render the component.

But if you change the reference of the object like:

newConsulationData = { ...consultation }
newConsultationData.date = /* some other date */;

It'll work fine.

In your scenario you might have trouble as you directly mutating the props array object, and passing the same array so I suggest you change the reference of consultations array: You'll need to

 newConsulations = [ ...consultations ];
 newConsultations[index of consultation].date = /* some other date */;

This should solve your problem. When working with react try not to mutate the objects if you want to re-render the component on the changes .

I think it may be related to data type.

The first approach is passing an Object to child component,

<ChildComponent consultation={consultation} />

the second approach is passing a String to child component.

<ChildComponent date={this.props.consultation.date} />

When the property date of the object consultation is changed, the object's index is not changed. I think react is referencing an object by its index. Object returns an index not the exact value. The index is the specific address where object is stored in memory. But a string or boolean or number returns the value directly.

I think react is comparing object by index, and comparing string by the value. In the first approach, index does not update, so re-rendering is not happening.


The third approach extracts the object properties with spread symbol.

<ChildComponent consultation={...consultation} />

I think react is referencing the property itself in this approach, as each property is extracted. It's no longer referencing the object, so re-render works.


(I used a few I think statement here, as it's just my guess. Still need official documents to support.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM