Reputation: 2234
My understanding was that PureComponent leverages shouldComponentUpdate()
and does a shallow comparison of state and props but I created a little example that operates differently than I expected.
The example app displays a list of people. Each list item has the ability to change its name. Try it out and inspect the code here.
In the parent component, I have a method that looks like this:
updateName(id, newName) {
const { people } = this.state
const idx = people.findIndex(person => person.id === id)
people[idx].name = newName
this.setState({ people })
}
The object that I'm passing back into setState
has the same reference as the previous object. In this case, shouldn't this component not update if it's doing a shallow comparison?
Secondly, another part that's unclear, I changed the child component Person
from PureComponent to Component and I'm still getting the benefit of only the child that was updated re-rendering (I'm doing a console log on each child render if you want to inspect that). Clearly this is something that React is doing internally to decide for the child whether it should update but I assumed that if the component was re-rendering it would re-render everything.
Upvotes: 3
Views: 574
Reputation: 4676
shouldn't this component not update if it's doing a shallow comparison?
Yep. And it isn't updating. You can see that the App
component's render()
method does not get called again after the initial render. This means the shallow comparison is working as you expect and the component is (correctly) not updating.
I believe the part that's throwing you off is this line in Person.prototype.handleSubmit()
:
this.setState({ value: '' })
Since oldState.value !== newState.value
, this will trigger a re-render on the modified Person
component, regardless of whether Person
is a PureComponent
or not.
If you take this line out, you will see that nothing updates (the behavior you're expecting).
Clearly this is something that React is doing internally to decide for the child whether it should update.
Nope, the child is setting its own state. The parent-child relationship is irrelevant here. React will update the child directly.
In the future you should try isolating your tests. The reason this confusion occurred is because you were relying on the render()
method to determine whether a child received new props. But the render()
method is called when a child receives new props AND when a child sets new state.
A better test for this situation would have been checking whether componentWillReceiveProps()
is called, thus eliminating state
from the picture:
componentWillReceiveProps(newProps) {
console.log('receiving props', newProps)
}
If you plug this into the Person
component, you will see that it does not get called. Exactly as you're expecting.
In short, React.PureComponent
works exactly as you were thinking.
Upvotes: 2