减少 React table 重新渲染
Reducing React table rerendering
我有一个包含两列的 table,每列都是 editable。 table 还包括添加新条目的能力。我 运行 遇到的问题是,每当编辑一行时,每一行都会重新呈现。对于较大的 tables,这会在编辑单行时导致明显的击键延迟。关于如何防止这种情况的任何想法?
我无法在“小”示例中重现性能问题,但 https://codesandbox.io/s/zen-williams-r8pii?file=/src/App.js 是基本功能。我试过在几个地方删除 React.memo 但无济于事(我是这方面的新手)
感谢您的帮助!
有些事情导致行重新呈现:
首先,行组件需要包裹在React.memo
const ThingRow = React.memo(({ thing, onUpdate }) => {
...
})
然后 onUpdate
也需要与 React.useCallback
一起记忆,并且为了将 useCallback 中的依赖性减少到仅 setThings
(见注释),您可以使用回调版本setThings
和 .map
更新项目
const ListOfThings = ({ things, setThings }) => {
const onUpdate = React.useCallback(
(thing) => {
setThings((prevThings) =>
prevThings.map((t) => (t.id === thing.id ? thing : t))
);
},
[setThings]
);
return (
<table>
<tbody>
{things.map((thing) => (
<ThingRow key={thing.id} thing={thing} onUpdate={onUpdate} />
))}
</tbody>
</table>
);
};
当遇到这种问题时,你需要寻找方法来记忆你传递的道具,尤其是回调,并减少钩子中的依赖
这是 codesandbox 分支 https://codesandbox.io/s/table-row-memoization-xs1d2?file=/src/App.js
注:根据react docs
React guarantees that setState function identity is stable and won’t change on re-renders
您可以尝试一些优化。
首先,如果您要处理大量数据,核心问题可能是您向 DOM 渲染了太多内容。
如果是这种情况,我将首先向 table 添加虚拟化或分页。
您可以使用库轻松添加虚拟化,例如使用来自 react-window:
的 FixedSizeList
import { FixedSizeList as List } from 'react-window';
const Row = ({ index, style }) => (
<div style={style}>Row {index}</div>
);
const Example = () => (
<List
height={150}
itemCount={1000}
itemSize={35}
width={300}
>
{Row}
</List>
);
这应该已经减少了任何性能问题,但如果您只想优化重新渲染:
React 的默认行为是渲染调用 useState setter 的当前组件,以及所有 child 组件,即使没有任何道具更改。
所以你应该在备忘录中包含 ListOfThings 和 ThingRow 以选择退出此行为:
const ListOfThings = memo({ things, setThings }) => {
...
});
const ThingRow = memo(({ thing, onUpdate }) => {
...
});
如果不这样做,更改不相关的标题输入将导致重新呈现所有内容。
最后,您要将内联事件处理程序 (onUpdate) 传递给 ThingRow。
这将为 ListOfThings 的每个渲染创建一个新函数 object,这将绕过我们之前进行的备忘录优化。
要对此进行优化,您可以使用 useCallback:
创建对该函数的持久引用
onUpdate={useCallback(
thing => setThings(prev => prev.map(t => t.id === thing.id ? thing : t)),
[setThings])}
请注意,当您依赖先前的更新值时,最好在 useState 中使用函数更新样式。
小免责声明:如果您遇到性能问题,我只会使用虚拟化/分页解决方案,而不会尝试针对重新渲染进行优化。 React 的默认渲染行为非常快,更改它可能会引入难以发现的与未更新的事物相关的错误。
我有一个包含两列的 table,每列都是 editable。 table 还包括添加新条目的能力。我 运行 遇到的问题是,每当编辑一行时,每一行都会重新呈现。对于较大的 tables,这会在编辑单行时导致明显的击键延迟。关于如何防止这种情况的任何想法?
我无法在“小”示例中重现性能问题,但 https://codesandbox.io/s/zen-williams-r8pii?file=/src/App.js 是基本功能。我试过在几个地方删除 React.memo 但无济于事(我是这方面的新手)
感谢您的帮助!
有些事情导致行重新呈现:
首先,行组件需要包裹在React.memo
const ThingRow = React.memo(({ thing, onUpdate }) => {
...
})
然后 onUpdate
也需要与 React.useCallback
一起记忆,并且为了将 useCallback 中的依赖性减少到仅 setThings
(见注释),您可以使用回调版本setThings
和 .map
更新项目
const ListOfThings = ({ things, setThings }) => {
const onUpdate = React.useCallback(
(thing) => {
setThings((prevThings) =>
prevThings.map((t) => (t.id === thing.id ? thing : t))
);
},
[setThings]
);
return (
<table>
<tbody>
{things.map((thing) => (
<ThingRow key={thing.id} thing={thing} onUpdate={onUpdate} />
))}
</tbody>
</table>
);
};
当遇到这种问题时,你需要寻找方法来记忆你传递的道具,尤其是回调,并减少钩子中的依赖
这是 codesandbox 分支 https://codesandbox.io/s/table-row-memoization-xs1d2?file=/src/App.js
注:根据react docs
React guarantees that setState function identity is stable and won’t change on re-renders
您可以尝试一些优化。 首先,如果您要处理大量数据,核心问题可能是您向 DOM 渲染了太多内容。 如果是这种情况,我将首先向 table 添加虚拟化或分页。 您可以使用库轻松添加虚拟化,例如使用来自 react-window:
的 FixedSizeListimport { FixedSizeList as List } from 'react-window';
const Row = ({ index, style }) => (
<div style={style}>Row {index}</div>
);
const Example = () => (
<List
height={150}
itemCount={1000}
itemSize={35}
width={300}
>
{Row}
</List>
);
这应该已经减少了任何性能问题,但如果您只想优化重新渲染: React 的默认行为是渲染调用 useState setter 的当前组件,以及所有 child 组件,即使没有任何道具更改。 所以你应该在备忘录中包含 ListOfThings 和 ThingRow 以选择退出此行为:
const ListOfThings = memo({ things, setThings }) => {
...
});
const ThingRow = memo(({ thing, onUpdate }) => {
...
});
如果不这样做,更改不相关的标题输入将导致重新呈现所有内容。
最后,您要将内联事件处理程序 (onUpdate) 传递给 ThingRow。 这将为 ListOfThings 的每个渲染创建一个新函数 object,这将绕过我们之前进行的备忘录优化。 要对此进行优化,您可以使用 useCallback:
创建对该函数的持久引用onUpdate={useCallback(
thing => setThings(prev => prev.map(t => t.id === thing.id ? thing : t)),
[setThings])}
请注意,当您依赖先前的更新值时,最好在 useState 中使用函数更新样式。
小免责声明:如果您遇到性能问题,我只会使用虚拟化/分页解决方案,而不会尝试针对重新渲染进行优化。 React 的默认渲染行为非常快,更改它可能会引入难以发现的与未更新的事物相关的错误。