React: 父组件重新呈现所有子级,即使是那些在状态更改时没有更改的子级

我还没有找到一个明确的答案,希望这不是重复。

我使用 React + Redux 作为一个简单的聊天应用程序。该应用程序由 InputBar、 MessageList 和 Container 组件组成。Container (正如您所想象的那样)包装了另外两个组件并连接到存储。我的消息以及当前消息(用户当前输入的消息)的状态保存在 Redux 存储中。简化结构:

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>
);
}
}

我遇到的问题发生在更新当前消息时。更新当前消息将触发一个更新存储的操作,该操作将更新通过容器并返回到 InputBar 组件的道具。

这是可行的,但是副作用是每次发生这种情况时,我的 MessageList 组件都会被重新呈现。MessageList 不接收当前消息,也没有任何理由更新。这是一个大问题,因为一旦 MessageList 变大,应用程序在每次更新当前消息时都会明显变慢。

我试过直接在 InputBar 组件中设置和更新当前消息状态(因此完全忽略了 Redux 体系结构) ,并“修复”了这个问题,但是如果可能的话,我想坚持使用 Redux 设计模式。

我的问题是:

  • 如果更新了父组件,React 是否总是更新该组件中的所有直接子组件?

  • 这里的正确方法是什么?

94687 次浏览

If a parent component is updated, does React always update all the direct children within that component?

No. React will only re-render a component if shouldComponentUpdate() returns true. By default, that method always returns true 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 returns true when the data has actually changed. If this.props.messages is always the same array, it could be as simple as this:

shouldComponentUpdate(nextProps) {
return (this.props.messages !== nextProps.messages);
}

You may also want to do some sort of deep comparison or comparison of the message IDs or something, it depends on your requirements.

EDIT: After a few years many people are using functional components. If that's the case for you then you'll want to check out React.memo. By default functional components will re-render every time just like the default behavior of class components. To modify that behavior you can use React.memo() and optionally provide an areEqual() function.

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 a React.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 info

Hope this helps anyone who is looking for the right way to fix this.

If a parent component is updated, does React always update all the direct children within that component? -> Yes , by default if parent changes all its direct children are re-rendered but that re-render doesn't necessarily changes the actual DOM , thats how React works , only visible changes are updated to real DOM.

What is the right approach here? -> To prevent even re-rendering of virtual DOM so to boost your performance further you can follow any of the following techniques:

  1. Apply ShouldComponentUpdate Lifecycle method - This is applied only if your child component is class based , you need to check the current props value with the prev props value ,and if they are true simply return false.

  2. Use Pure Component -> This is just a shorter version to above method , again works with class based components

  3. Use React memo -> this is the best way to prevent Rerendering even if you have functional components ,you simply need to wrap your components export with React.memo like : export default React.memo(MessageList)

Hope that helps!

If you're using map to render child components and using a unique key on them (something like uuid()), maybe switch back to using the i from the map as key. It might solve the re-rendering issue.

Not sure about this approach, but sometimes it fixes the issue