我一直无法找到明确的答案,希望这不是重复的。
我正在将 React + Redux 用于一个简单的聊天应用程序。该应用程序由 InputBar、MessageList 和 Container 组件组成。 Container(如您所想)包装了其他两个组件并连接到 store。我的消息状态以及当前消息(用户当前正在输入的消息)都保存在 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 是否总是更新该组件中的所有直接子组件?
这里的正确方法是什么?
如果父组件被更新,React 是否总是更新该组件中的所有直接子组件?
不会。如果 shouldComponentUpdate()
返回 true
,React 只会重新渲染组件。默认情况下,该方法总是返回 true
以避免对新手造成任何微妙的错误(正如 William B 指出的那样,除非发生变化,否则 DOM 不会真正更新,从而降低影响)。
为防止子组件不必要地重新呈现,您需要实现 shouldComponentUpdate
方法,使其仅在数据实际更改时才返回 true
。如果 this.props.messages
始终是同一个数组,它可以像这样简单:
shouldComponentUpdate(nextProps) {
return (this.props.messages !== nextProps.messages);
}
您可能还想对消息 ID 或其他内容进行某种深度比较或比较,这取决于您的要求。
编辑:几年后,很多人都在使用功能组件。如果您遇到这种情况,那么您需要查看 React.memo。默认情况下,功能组件每次都会重新渲染,就像类组件的默认行为一样。要修改该行为,您可以使用 React.memo()
并可选择提供 areEqual()
函数。
如果父组件被更新,React 是否总是更新该组件中的所有直接子组件? -> 是的,默认情况下,如果父级更改,其所有直接子级都将重新渲染,但重新渲染不一定会更改实际的 DOM,这就是 React 的工作原理,只有可见的更改会更新为真实的 DOM。
这里的正确方法是什么? -> 为了防止虚拟 DOM 的重新渲染以进一步提高性能,您可以遵循以下任何技术:
Apply ShouldComponentUpdate Lifecycle 方法 - 仅当您的子组件基于类时才应用此方法,您需要使用 prev props 值检查当前 props 值,如果它们为 true,则返回 false。使用纯组件->这只是上述方法的较短版本,同样适用于基于类的组件使用 React 备忘录->即使您有功能组件,这是防止重新渲染的最佳方法,您只需将组件导出包装为React.memo like : 导出默认 React.memo(MessageList)
希望有帮助!
const Parent = ({children}) => <div> {children} </div> , const App = () => <Parent><Child></Parent>
如果父组件道具已更改,它将重新渲染使用 React.Component
语句制作的所有子组件。
尝试将您的 <MessageList>
组件设置为 React.PureComponent
以规避这一点。
根据 React 文档: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.
检查此 link 了解更多信息
希望这可以帮助任何正在寻找解决此问题的正确方法的人。
如果您使用 map
呈现子组件并在它们上使用唯一键(类似于 uuid()
),则可能切换回使用地图中的 i
作为键。它可能会解决重新渲染的问题。
不确定这种方法,但有时它可以解决问题
不定期副业成功案例分享
componentDidMount
上没有更新什么?(this.props.messages !== nextProps.messages)
),才会显示所有消息shouldComponentUpdate
,父级是否总是会重新渲染它的所有子级?React.Component
继承(而不是React.PureComponent
或类似的东西),那么是的,它总是会重新渲染。