captDaylight captDaylight - 1 month ago 15
React JSX Question

How does PureComponent work?

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.

Answer Source

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.