redux React:父组件重新呈现所有子组件,即使是那些状态没有改变的子组件

kqhtkvqz  于 2023-06-23  发布在  React
关注(0)|答案(4)|浏览(177)

我还没有找到一个明确的答案,希望这不是重复。
我正在使用React + Redux作为一个简单的聊天应用程序。该应用程序由InputBar、MessageList和Container组件组成。Container(如您所想) Package 了另外两个组件并连接到存储。我的消息和当前消息(用户当前正在键入的消息)的状态都保存在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组件的props。
这是可行的,但是一个副作用是每次发生这种情况时,我的MessageList组件都会重新呈现。MessageList未收到当前消息,并且没有任何更新的理由。这是一个大问题,因为一旦MessageList变大,应用程序每次更新当前消息时都会明显变慢。
我已经尝试直接在InputBar组件中设置和更新当前消息状态(因此完全忽略了Redux架构)并“修复”了问题,但是如果可能的话,我希望坚持使用Redux设计模式。
我的问题是:

  • 如果父组件被更新,React是否总是更新该组件中的所有直接子组件?
  • 什么是正确的方法呢?
qjp7pelc

qjp7pelc1#

如果父组件被更新,React是否总是更新该组件中的所有直接子组件?
不可以。React只会在shouldComponentUpdate()返回true时重新渲染组件。默认情况下,该方法总是返回true,以避免对新用户造成任何细微的错误(正如William B所指出的,除非发生更改,否则DOM实际上不会更新,从而降低了影响)。
为了防止您的子组件不必要地重新呈现,您需要以这样一种方式实现shouldComponentUpdate方法,即它仅在数据实际更改时返回true。如果this.props.messages总是相同的数组,它可以像这样简单:

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

您可能还希望进行某种深度比较或比较消息ID或其他内容,这取决于您的需求。
编辑:几年后,许多人开始使用功能组件。如果你是这样的话,那么你会想看看React.memo。默认情况下,函数组件每次都会重新呈现,就像类组件的默认行为一样。要修改该行为,您可以使用React.memo(),并可选地提供areEqual()函数。

5n0oy7gb

5n0oy7gb2#

如果父组件被更新,React是否总是更新该组件中的所有直接子组件?->是的,默认情况下,如果parent更改,则其所有直接子对象都将重新渲染,但重新渲染不一定会更改实际DOM,这就是React的工作方式,只有可见的更改才会更新到真实的的DOM。
这里的正确方法是什么?->为了防止甚至重新渲染虚拟DOM,以便进一步提高性能,您可以使用以下任何技术:

  1. ApplyShouldComponentUpdateLifecycle方法-仅当您的子组件是基于类的时才应用此方法,您需要检查当前props值与prev props值,如果它们为true,则只需返回false。
    1.使用纯组件->这只是上述方法的一个较短的版本,同样可以使用基于类的组件
    1.使用React memo->这是防止重新渲染的最好方法,即使你有功能组件,你只需要用React.memo Package 你的组件导出,比如:export default React.memo(MessageList)

**编辑:**请注意:如果你传递一个函数或任何对象作为prop给你的子组件,那么即使你使用React.memo,子组件仍然会被重新渲染。这是因为函数在JavaScript中是对象,每次父级重新渲染时都会创建一个新的函数对象,所以React将其视为不同的prop。示例:

const onClickHandler = () => {
     console.log('button is clicked')
    }

return (
  <Button onClick={onClickHandler}>
)

在上面的例子中,如果渲染了Parent,Button组件总是会被重新渲染,为了解决上面的问题,我们可以使用另一个React钩子:useCallback-这个钩子允许在重新渲染之间维护相同的对象或函数。

const onClickHandler = useCallback(() => {
     console.log('button is clicked')
    },[])

return (
  <Button onClick={onClickHandler}>
)

现在,如果你在Button组件中使用React.memo,它不会重新渲染,除非 prop 被实际改变。
希望有帮助!

vtwuwzda

vtwuwzda3#

如果父组件props发生了变化,它将重新呈现所有使用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.检查此链接以获取更多信息
希望这能帮助任何正在寻找正确方法来解决这个问题的人。

6jygbczu

6jygbczu4#

如果你使用map来渲染子组件,并在它们上使用一个唯一的键(类似于uuid()),也许可以切换回使用map中的i作为键。它可能会解决重新渲染的问题。
我不确定这种方法,但有时它可以解决问题

相关问题