当一项更改时,React 会重新渲染整个列表

Posted

技术标签:

【中文标题】当一项更改时,React 会重新渲染整个列表【英文标题】:React re-renders entire list when one item is changed 【发布时间】:2018-04-10 12:02:00 【问题描述】:

我有一个简单的 React 应用程序,它可以呈现 5000 种产品的名称和价格。价格是可编辑的,更改后价格会反映在状态中。

https://github.com/TonyCaffer/thinking-in-react-1

App.js 通过 onChangePrice 函数管理状态并处理价格变化,该函数被传递给 ProductTable 和每个 ProductRow

我使用 immutability-helpers 并且我专门只更改了已更改产品的状态记录。

但每次更改都会有明显的一秒延迟,因为 React 正在重新渲染所有产品。每个产品都有一个关键属性,我认为这有助于 React 只重新渲染必要的组件。

在生产版本中,它的滞后性较小,但所有产品都会重新渲染,这是我要解决的根本问题。

为什么要重新渲染所有产品组件?是因为我通过高级 ProductTable 传递 this.state.products 从而触发列表的总重绘?如果是这样,当状态在列表中时,每个 ProductRow 如何管理自己的记录状态?

【问题讨论】:

它不会停止重新渲染。他们的“关键”事物将调用之前调用的相同组件,并调用componentWillUpdate 而不是componentWillMount。要停止渲染,请使用shouldComponentUpdate 停止重新渲染。 【参考方案1】:

React 将更新安排在两个阶段:协调器阶段(或渲染阶段,因为它涉及我们定义的组件的渲染方法)和提交阶段。当状态更新时,React 无论如何都会启动更新过程。使用适当的 shouldComponentUpdate 可以帮助您减少子组件中的更新次数

可能的解决方案:为ProductRow 使用shouldComponentUpdate,如下所示:

shouldComponentUpdate(nextProps) 
  if (
    this.props.guid !== nextProps.guid
    || // similarly check if the other new props are different
  ) 
    return true;
  
  return false

上述检查将确保当父级检测到 setState 并在新的 React Fiber 的工作循环中安排更新时,不会重新计算子组件并且提交阶段完全跳过任何 DOM 更新。

Lin Clark explains the two phases 真的很好。它肯定会帮助您了解 React Fiber 如何管理更新。

您可以查看 React Virtualised 以提高对极长列表的感知性能。

【讨论】:

我添加了一个componentShouldUpdate函数。现在开发中的更新滞后,但生产没有滞后。我会认为这是一个很好的结果,并确保将我的应用程序架构成永远不会有这么大的列表。在我承诺之前,我想突破 React 的极限。 查看更新后的github:github.com/TonyCaffer/thinking-in-react-1

以上是关于当一项更改时,React 会重新渲染整个列表的主要内容,如果未能解决你的问题,请参考以下文章

为啥组件在单击和状态更改时会重新渲染?

React Native:为啥 FlatList 会在数据更改时完全重新渲染?

当在 ReactJs React-Redux 中仅创建或更新列表中的一个项目时,如何停止重新渲染整个项目列表?

属性更改时如何重新渲染反应组件

如何防止 react 重新渲染整个组件?

React 组件不会在值更改时重新渲染并显示 CSS 更改