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

Nic*_*ley 33 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>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

更新当前消息时出现的问题.更新当前消息会触发更新存储的操作,该操作会更新通过容器并返回到InputBar组件的props.

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

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

我的问题是:

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

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

GJK*_*GJK 61

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

不会.Ract只会在shouldComponentUpdate()返回时重新渲染一个组件true.默认情况下,该方法总是返回true以避免新手的任何微妙错误(并且正如William B所指出的,除非发生变化,否则DOM实际上不会更新,从而降低了影响).

为了防止您的子组件不必要地重新渲染,您需要以shouldComponentUpdatetrue在数据实际更改时返回的方式实现该方法.如果this.props.messages总是相同的数组,它可能就像这样简单:

shouldComponentUpdate(nextProps) {
    return (this.props.messages !== nextProps.messages);
}
Run Code Online (Sandbox Code Playgroud)

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

  • 完美,正是我正在寻找的答案! (4认同)
  • 所以如果你不实现 `shouldComponentUpdate`,父级是否总是重新渲染它的所有子级? (4认同)
  • 我不确定你是什么意思。什么在`componentDidMount` 上没有更新? (2认同)
  • 如果你直接从 `React.Component`(而不是 `React.PureComponent` 或类似的东西)继承,那么是的,它总是会重新渲染。 (2认同)

lok*_*shj 41

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

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

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

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

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

希望有帮助!

  • 谢谢。我一直在尝试使用usememo,但没有成功。正如你所说,我所要做的就是用 React.memo() 包装组件。 (2认同)

sid*_*idd 5

如果父级组件道具已更改,它将重新渲染使用React.Componentstatement 制作的所有子级。

尝试使<MessageList>组件成为A React.PureComponent来逃避此操作。

根据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.查看此链接以获取更多信息

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