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

时间:2016-11-26 15:38:04

标签: reactjs redux

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

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

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

4 个答案:

答案 0 :(得分:47)

  

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

没有。如果shouldComponentUpdate()返回true,则React将仅重新呈现组件。默认情况下,该方法始终返回true以避免新手的任何微妙错误(正如William B所指出的,除非发生变化,否则DOM实际上不会更新,从而降低了影响力。)

为防止您的子组件不必要地重新渲染,您需要实现shouldComponentUpdate方法,使其在数据实际更改时仅返回true。如果this.props.messages始终是相同的数组,则可能就像这样简单:

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

您可能还希望对消息ID或其他内容进行某种深度比较或比较,这取决于您的要求。

答案 1 :(得分:19)

如果上级组件已更新,React会始终更新该组件内的所有直接子级吗? ->是的,默认情况下,如果父项更改了其所有直接子级,则将重新渲染,但重新渲染并不一定会更改实际DOM,这就是React的工作方式,只有可见的更改会更新为真实DOM。

这里正确的方法是什么? ->为防止甚至重新呈现虚拟DOM,从而进一步提高性能,您可以采用以下任何一种技术:

  1. 应用 ShouldComponentUpdate 生命周期方法-仅在子组件基于类,需要使用prev props值检查当前props值以及它们是否为true时才适用返回false。

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

  3. 使用反应备忘录->这是防止重新渲染的最佳方法,即使您具有功能组件,也只需使用React.memo包装组件导出即可,例如:{{1 }}

希望有帮助!

答案 2 :(得分:3)

如果父级组件道具已更改,它将重新渲染使用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以获得更多信息

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

答案 3 :(得分:0)

如果您正在使用map渲染子组件并在其上使用唯一键(例如uuid()),则可以切换回使用地图中的i作为键。也许可以解决重新渲染的问题。

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