使用 react-window 防止 DOM 元素在虚拟化树组件中重新渲染
Prevent DOM element re-render in virtualized tree component using react-window
我想重新实现一个树组件来提高它的性能。我使用了来自 react-window 的 FixedSizeList。它的工作相对较好。它甚至可以处理 100,000 个树节点。
我的问题是,我想为树节点的小开口三角形设置动画。以下css负责动画:
.tree-branch::after {
content: '';
display: block;
width: 0;
height: 0;
margin-top: 1px;
margin-left: 23px;
border-top: 6px solid transparent;
border-bottom: 6px solid transparent;
border-left: 6px solid rgba(0, 0, 0, 0.7);
opacity: 0.7;
position: absolute;
top: 0;
left: -36px;
transform: rotate(90deg);
animation-duration: 0.3s;
}
.tree-item-closed::after {
transform: rotate(0deg);
}
动画不工作。因为在每次打开和关闭所有列表元素 div 时都会重新渲染。然后我尝试为列表添加 itemKey 属性 以帮助 React 重用 div。
<List
className="List"
height={height}
itemCount={flattenedData.length}
itemSize={32}
width={width}
itemKey={index => flattenedData[index].id} // key defined
>
{Row}
</List>
也不行。 div 不会更新,而是重新呈现整个 div。这个问题有合适的解决方案吗?如何防止重新渲染?
这里是整个例子:https://codesandbox.io/s/a-quick-react-tree-component-based-on-react-window-tyxnm
要防止 react-window
来自 re-rendering 列表中的每个项目,您需要:
- 记住你的 row-rendering 函数
- 将该函数移出父函数的范围
- 使用
itemData
属性在父组件和 per-row 渲染函数之间进行通信。
这是 react-window 示例沙箱中使用的策略:https://codesandbox.io/s/github/bvaughn/react-window/tree/master/website/sandboxes/memoized-list-items
这是一个使用您的代码的示例:
https://codesandbox.io/s/a-quick-react-tree-component-based-on-react-window-8psp0
使用 useMemo
可能有更简单的方法,但我想不出来。
如果您使用 Chrome 开发工具检查 DOM 节点,您会发现 DOM 节点不再是整个树的 re-created 当一个节点展开。这消除了您之前在选择新节点时看到的闪烁(在 Chrome,但在 Firefox 中没有)。
但还有一些其他因素会阻止您的旋转动画正常工作。在我上面链接的 CodeSandbox 示例中,我在 border
属性上添加了一些动画,以显示某些 CSS 属性的动画是如何工作的,但是 transform
CSS 属性的动画不管用。我怀疑此问题与 react-window
无关,因此您可能希望单独调试它以找出为什么您的转换没有动画但其他属性动画正常。
我想重新实现一个树组件来提高它的性能。我使用了来自 react-window 的 FixedSizeList。它的工作相对较好。它甚至可以处理 100,000 个树节点。
我的问题是,我想为树节点的小开口三角形设置动画。以下css负责动画:
.tree-branch::after {
content: '';
display: block;
width: 0;
height: 0;
margin-top: 1px;
margin-left: 23px;
border-top: 6px solid transparent;
border-bottom: 6px solid transparent;
border-left: 6px solid rgba(0, 0, 0, 0.7);
opacity: 0.7;
position: absolute;
top: 0;
left: -36px;
transform: rotate(90deg);
animation-duration: 0.3s;
}
.tree-item-closed::after {
transform: rotate(0deg);
}
动画不工作。因为在每次打开和关闭所有列表元素 div 时都会重新渲染。然后我尝试为列表添加 itemKey 属性 以帮助 React 重用 div。
<List
className="List"
height={height}
itemCount={flattenedData.length}
itemSize={32}
width={width}
itemKey={index => flattenedData[index].id} // key defined
>
{Row}
</List>
也不行。 div 不会更新,而是重新呈现整个 div。这个问题有合适的解决方案吗?如何防止重新渲染?
这里是整个例子:https://codesandbox.io/s/a-quick-react-tree-component-based-on-react-window-tyxnm
要防止 react-window
来自 re-rendering 列表中的每个项目,您需要:
- 记住你的 row-rendering 函数
- 将该函数移出父函数的范围
- 使用
itemData
属性在父组件和 per-row 渲染函数之间进行通信。
这是 react-window 示例沙箱中使用的策略:https://codesandbox.io/s/github/bvaughn/react-window/tree/master/website/sandboxes/memoized-list-items
这是一个使用您的代码的示例: https://codesandbox.io/s/a-quick-react-tree-component-based-on-react-window-8psp0
使用 useMemo
可能有更简单的方法,但我想不出来。
如果您使用 Chrome 开发工具检查 DOM 节点,您会发现 DOM 节点不再是整个树的 re-created 当一个节点展开。这消除了您之前在选择新节点时看到的闪烁(在 Chrome,但在 Firefox 中没有)。
但还有一些其他因素会阻止您的旋转动画正常工作。在我上面链接的 CodeSandbox 示例中,我在 border
属性上添加了一些动画,以显示某些 CSS 属性的动画是如何工作的,但是 transform
CSS 属性的动画不管用。我怀疑此问题与 react-window
无关,因此您可能希望单独调试它以找出为什么您的转换没有动画但其他属性动画正常。