我还没有找到一个明确的答案,希望这不是重复。
我正在使用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是否总是更新该组件中的所有直接子组件?
- 什么是正确的方法呢?
4条答案
按热度按时间qjp7pelc1#
如果父组件被更新,React是否总是更新该组件中的所有直接子组件?
不可以。React只会在
shouldComponentUpdate()
返回true
时重新渲染组件。默认情况下,该方法总是返回true
,以避免对新用户造成任何细微的错误(正如William B所指出的,除非发生更改,否则DOM实际上不会更新,从而降低了影响)。为了防止您的子组件不必要地重新呈现,您需要以这样一种方式实现
shouldComponentUpdate
方法,即它仅在数据实际更改时返回true
。如果this.props.messages
总是相同的数组,它可以像这样简单:您可能还希望进行某种深度比较或比较消息ID或其他内容,这取决于您的需求。
编辑:几年后,许多人开始使用功能组件。如果你是这样的话,那么你会想看看React.memo。默认情况下,函数组件每次都会重新呈现,就像类组件的默认行为一样。要修改该行为,您可以使用
React.memo()
,并可选地提供areEqual()
函数。5n0oy7gb2#
如果父组件被更新,React是否总是更新该组件中的所有直接子组件?->是的,默认情况下,如果parent更改,则其所有直接子对象都将重新渲染,但重新渲染不一定会更改实际DOM,这就是React的工作方式,只有可见的更改才会更新到真实的的DOM。
这里的正确方法是什么?->为了防止甚至重新渲染虚拟DOM,以便进一步提高性能,您可以使用以下任何技术:
1.使用纯组件->这只是上述方法的一个较短的版本,同样可以使用基于类的组件
1.使用React memo->这是防止重新渲染的最好方法,即使你有功能组件,你只需要用React.memo Package 你的组件导出,比如:
export default React.memo(MessageList)
**编辑:**请注意:如果你传递一个函数或任何对象作为prop给你的子组件,那么即使你使用React.memo,子组件仍然会被重新渲染。这是因为函数在JavaScript中是对象,每次父级重新渲染时都会创建一个新的函数对象,所以React将其视为不同的prop。示例:
在上面的例子中,如果渲染了Parent,Button组件总是会被重新渲染,为了解决上面的问题,我们可以使用另一个React钩子:useCallback-这个钩子允许在重新渲染之间维护相同的对象或函数。
现在,如果你在Button组件中使用React.memo,它不会重新渲染,除非 prop 被实际改变。
希望有帮助!
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.
检查此链接以获取更多信息希望这能帮助任何正在寻找正确方法来解决这个问题的人。
6jygbczu4#
如果你使用
map
来渲染子组件,并在它们上使用一个唯一的键(类似于uuid()
),也许可以切换回使用map中的i
作为键。它可能会解决重新渲染的问题。我不确定这种方法,但有时它可以解决问题