【问题标题】:React: Parent component re-renders all children, even those that haven't changed on state changeReact:父组件重新渲染所有子组件,即使是那些在状态更改时没有更改的子组件
【发布时间】:2017-04-10 17:46:07
【问题描述】:

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

我正在将 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>
    );
  }
}

我在更新当前消息时遇到的问题。更新当前消息会触发更新 store 的操作,该操作会更新通过容器并返回到 InputBar 组件的 props。

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

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

我的问题是:

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

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

【问题讨论】:

  • 即使运行了 render(),它也应该很快——除非有实际的变化,否则它根本不会更新 DOM。所以重新渲染孩子对我来说是最安全的行为。但是我实际上不知道 react 是否应该这样做,所以这不是答案

标签: reactjs redux


【解决方案1】:

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

【讨论】:

  • 完美,正是我想要的答案!
  • 虽然这可行,但我发现它不会在 componentDidMount 上更新。知道解决方法是什么吗?
  • 我不确定你的意思。 componentDidMount 上没有更新什么?
  • 那么如果你不实现shouldComponentUpdate,父级是否总是会重新渲染它的所有子级?
  • 如果你直接从React.Component(而不是React.PureComponent或类似的东西)继承,那么是的,它总是会重新渲染。
【解决方案2】:

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

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

  1. 应用 ShouldComponentUpdate 生命周期方法 - 仅当您的子组件基于类时才应用此方法,您需要使用 prev props 值检查当前 props 值,如果它们为 true返回 false。

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

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

希望有帮助!

【讨论】:

  • 谢谢。我一直在尝试使用usememo,但是没有用。正如你所说,我所要做的就是用 React.memo() 包装组件。
【解决方案3】:

如果父组件的 props 发生了变化,它将重新渲染使用 React.Component 语句制作的所有子组件。

尝试将您的 &lt;MessageList&gt; 组件设置为 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 了解更多信息

希望这对正在寻找解决此问题的正确方法的人有所帮助。

【讨论】:

    【解决方案4】:

    如果您使用map 渲染子组件并在它们上使用唯一键(类似于uuid()),则可能切换回使用映射中的i 作为键。它可能会解决重新渲染问题。

    不确定这种方法,但有时它可以解决问题

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-01-08
      • 2020-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-04
      • 2021-04-06
      相关资源
      最近更新 更多