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

新手上路,请多包涵

我一直无法找到明确的答案,希望这不是重复的。

我正在将 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 是否总是更新该组件中的所有直接子组件?

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

原文由 Nicholas Haley 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.3k
2 个回答

如果父组件被更新,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() 函数。

原文由 GJK 发布,翻译遵循 CC BY-SA 4.0 许可协议

如果更新父组件,React 是否总是更新该组件中的所有直接子组件? -> 是的,默认情况下,如果父级更改,则重新渲染其所有直接子级,但重新渲染不一定会更改实际的 DOM,这就是 React 的工作方式,只有可见的更改才会更新为真实的 DOM。

这里正确的方法是什么? -> 为了防止甚至重新渲染虚拟 DOM 以进一步提高性能,您可以遵循以下任何技术:

  1. 应用 ShouldComponentUpdate Lifecycle 方法 - 这仅在您的子组件基于类时应用,您需要使用前一个道具值检查当前道具值,如果它们为真,则返回 false。

  2. 使用 纯组件-> 这只是上述方法的一个较短版本,同样适用于基于类的组件

  3. 使用 React 备忘录-> 这是防止重新渲染的最佳方法,即使你有功能组件,你只需要用 React.memo 包装你的组件导出,如: export default React.memo(MessageList)

希望有帮助!

原文由 lokeshj 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进