[英]React.memo component re-rendering without checking isEquals when expected
Edit: Here is a working example: https://codesandbox.io/s/gracious-silence-5n4pv Why does pressing the button re-render all the cells, but scrolling not?编辑:这是一个工作示例: https : //codesandbox.io/s/gracious-silence-5n4pv为什么按下按钮会重新渲染所有单元格,但不滚动?
I'm trying to improve performance, so I've extracted a component into something with simple props that's more React.memo
friendly:我正在尝试提高性能,所以我已经将一个组件提取到一些具有更
React.memo
友好的简单道具的东西中:
interface DataTableCellProps {
header: string;
value: string;
isRepeatedValue: boolean;
width: number;
}
const DataCell = styled.div<{ width: number; isRepeatedValue: boolean }>`
padding-left: 0.5rem;
padding-right: 0.5rem;
width: ${props => props.width}px;
color: ${props => (props.isRepeatedValue ? grey : lightGrey)};
display: flex;
`;
/** Data table cells. A pure component that can be memoised easily (all props are simple types) */
const DataTableCell = React.memo(
(props: DataTableCellProps) => {
console.log("Rendering");
return (
<DataCell
role="cell"
area-header={props.header}
width={props.width}
isRepeatedValue={props.isRepeatedValue}
>
<Tooltip title={props.value} placement="bottom-start" enterDelay={500}>
<span className="text-truncate">{props.value}</span>
</Tooltip>
</DataCell>
);
},
(a, b) => {
console.log("Are props equal?");
return true;
}
);
It only takes strings, booleans and numbers as an input.它只需要字符串、布尔值和数字作为输入。 But I've added a cusom
isEqual
check to log, and for now forced it to always say it's equal.但是我在日志中添加了一个 cusom
isEqual
检查,现在强制它总是说它是平等的。 By my understanding, it should always return the cached component, and never re-render unless they key changes.根据我的理解,它应该始终返回缓存的组件,除非它们的关键更改,否则永远不要重新渲染。
Here's where it's rendered, stripped of everything not functional:这是渲染的地方,去掉了所有不起作用的东西:
const DataTableBody = (props: DataTableBodyProps) => (<FixedSizeList
width={300}
height={300}
itemCount={props.rows.length}
itemSize={35}
outerRef={props.containerRef}
outerElementType={CustomScrollbarsVirtualList}
>
{({ index, style }) => {
const row = props.rows[index];
props.prepareRow(row);
return (
<div
style={{
...style,
transform: `translate(${props.horizontalScroll}px, 0)`,
display: "flex"
}}
>
{row.cells.map((cell: any) => (
<DataTableCell
key={cell.getCellProps().key}
value={cell.value}
header={cell.column.Header}
width={
props.widths[cell.column.Header] ||
props.defaultColumnWidth
}
isRepeatedValue={cell.isRepeatedValue}
/>
))}
</div>
);
}}
</FixedSizeList>);
I logged the key (from react-tables
), and it is a stable string unique for each cell.我记录了密钥(来自
react-tables
),它是每个单元格唯一的稳定字符串。
When the prop horizontalScroll
in the above example changes, which would change the div
's rendering, but shouldn't affect the DataTableCell
as it's not passed in props, and the key hasn't changed - I get the console log Rendering
printed out hundreds of time.当上面例子中的 prop
horizontalScroll
改变时,这会改变div
的渲染,但不应该影响DataTableCell
因为它没有在 props 中传递,而且键没有改变 - 我得到控制台日志Rendering
打印出数百时间。 I don't get Are props equal?
我不明白
Are props equal?
However, it works fine with scrolling the component!但是,它可以很好地滚动组件! When scrolling vertically, the
style
will be changing, it re-renders, I see a whole load of Are props equal?
垂直滚动时,
style
会改变,它会重新渲染,我看到Are props equal?
, but only a handful of Rendering
logs. ,但只有少数
Rendering
日志。 I'm pretty confident the ones with a new key are being rendered, and existing keys are being checked for equality and NOT being rendered.我非常有信心正在呈现具有新密钥的密钥,并且正在检查现有密钥的相等性而不是呈现密钥。
So why does it not work with horizontalScroll
?那么为什么它不适用于
horizontalScroll
呢?
Found a solution.找到了解决办法。 It was react-window.
这是反应窗口。 Following their guide and passing
itemData
prop into the list, and avoiding using external values in the RenderRow
prevented it recreating components:以下其引导并传递
itemData
丙到列表中,并且在使用外部值避免RenderRow
防止它重新创建组件:
https://react-window.now.sh/#/examples/list/memoized-list-items https://react-window.now.sh/#/examples/list/memoized-list-items
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.