I haven't been able to find a clear answer to this, hope this isn't repetitive.
I am using React + Redux for a simple chat app. The app is comprised of an InputBar, MessageList, and Container component. The Container (as you might imagine) wraps the other two components and is connected to the store. The state of my messages, as well as current message (the message the user is currently typing) is held in the Redux store. Simplified structure:
class ContainerComponent extends Component {
...
render() {
return (
<div id="message-container">
<MessageList
messages={this.props.messages}
/>
<InputBar
currentMessage={this.props.currentMessage}
updateMessage={this.props.updateMessage}
onSubmit={this.props.addMessage}
/>
</div>
);
}
}
The issue I'm having occurs when updating the current message. Updating the current message triggers an action that updates the store, which updates the props passing through container and back to the InputBar component.
This works, however a side effect is that my MessageList component is getting re-rendered every time this happens. MessageList does not receive the current message and doesn't have any reason to update. This is a big issue because once the MessageList becomes big, the app becomes noticeably slower every time current message updates.
I've tried setting and updating the current message state directly within the InputBar component (so completely ignoring the Redux architecture) and that "fixes" the problem, however I would like to stick with Redux design pattern if possible.
My questions are:
If a parent component is updated, does React always update all the direct children within that component?
What is the right approach here?
No. React will only re-render a component if
shouldComponentUpdate()
returnstrue
. By default, that method always returnstrue
to avoid any subtle bugs for newcomers (and as William B pointed out, the DOM won't actually update unless something changed, lowering the impact).To prevent your sub-component from re-rendering unnecessarily, you need to implement the
shouldComponentUpdate
method in such a way that it only returnstrue
when the data has actually changed. Ifthis.props.messages
is always the same array, it could be as simple as this:You may also want to do some sort of deep comparison or comparison of the message IDs or something, it depends on your requirements.
If parent component props have changed it will re-render all of its children which are made using
React.Component
statement.Try making your
<MessageList>
component aReact.PureComponent
to evade this.According to React docs:
In the future React may treat shouldComponentUpdate() as a hint rather than a strict directive, and returning false may still result in a re-rendering of the component.
check this link for more infoHope this helps anyone who is looking for the right way to fix this.