首页 > 解决方案 > React.memo 组件重新渲染而不在预期时检查 isEquals

问题描述

编辑:这是一个工作示例:https ://codesandbox.io/s/gracious-silence-5n4pv为什么按下按钮会重新渲染所有单元格,但不能滚动?

我正在尝试提高性能,因此我将一个组件提取到具有更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;
  }
);

它只需要字符串、布尔值和数字作为输入。但是我添加了一个自定义isEqual检查来记录,现在强制它总是说它是平等的。据我了解,它应该始终返回缓存的组件,并且永远不要重新渲染,除非它们发生关键变化。

这是它被渲染的地方,去掉了所有不起作用的东西:

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>);

我记录了密钥(来自react-tables),它是每个单元格唯一的稳定字符串。

horizontalScroll上面示例中的道具发生变化时,这会改变div' 的渲染,但不应该影响 ,DataTableCell因为它没有传入道具,并且密钥没有改变 - 我得到控制台日志Rendering打印了数百次。我不明白Are props equal?

但是,它可以很好地滚动组件!垂直滚动时,style会发生变化,它会重新渲染,我看到一大堆Are props equal?,但只有少数Rendering日志。我非常有信心正在渲染具有新密钥的密钥,并且正在检查现有密钥是否相等而不是被渲染。

那么为什么它不起作用horizontalScroll呢?

标签: reactjs

解决方案


找到了解决方案。这是反应窗口。遵循他们的指南并将itemDataprop 传递到列表中,并避免在RenderRow阻止它重新创建组件中使用外部值:

https://react-window.now.sh/#/examples/list/memoized-list-items


推荐阅读