简体   繁体   English

React.memo 组件在预期时重新渲染而不检查 isEquals

[英]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.

相关问题 使用 React.memo() 记忆的组件不断重新渲染 - Component memoized with React.memo() keeps re-rendering 比较 React.memo 组件中的 prevProps 和 nextProps 以防止不必要的重新渲染,但这很有趣 - Comparing prevProps and nextProps in a React.memo Component to prevent unnecessary re-rendering but it's acting funny 我如何使用 React.memo 来防止重新渲染? - How do I use React.memo to prevent re-rendering? 即使在使用 memo 和 useCallback 后 React 组件也会重新渲染 - React component re-rendering even after using memo and useCallback 使用React挂钩和备忘录时如何防止子组件重新渲染? - How to prevent child component from re-rendering when using React hooks and memo? React 备忘录允许重新渲染到 forwardRef - React memo allowing re-rendering to forwardRef 为什么 React.Memo() 不断渲染我的组件 - Why React.Memo() keeps rendering my component 我使用 React hooks 和 React memo 来防止我的功能组件重新渲染,但不起作用? - I use React hooks and React memo to prevent my functional component from re-rendering ,but not work? 如何防止我的功能组件使用 React 备忘录或 React 钩子重新渲染? - How can I prevent my functional component from re-rendering with React memo or React hooks? 重新渲染React组件 - re-rendering React Component
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM