如何防止在 react-window 的列表组件内重新呈现 children

How to prevent rerendering of children inside List component of react-window

问题

我正在尝试实现一种行为,当仅更新列表中已更改的项目并使用新数据重新呈现时。

我写了一个组件,它在计时器关闭时正在更新:

import { FixedSizeList as List } from 'react-window';


function ProfilesList() {
   ...

   // Here is an effect which fetches new data every time and component is rerendered with new data

   React.useEffect(() => {
        const timer = setInterval(() => {
            dispatch(loadProfilesList());
        }, intervalTime);
        return () => {
            clearInterval(timer);
        };
    }, [dispatch]);

    ...

    return (
       <List height={758} width={625} itemSize={82} itemCount={filteredProfiles.length}>
            {({ index, style }: { index: number; style: any }): React.ReactElement => {
                return (
                    <div style={style} key={index}>
                        <Tooltip title={t`stop` as string}>
                            <Button>lalla</Button>
                        </Tooltip>
                    </div>
                );
            }}
        </List>
    );

因此,当计时器关闭时,所有项目都会重新呈现,但其中 none 实际上没有改变,这导致工具提示的外观闪烁:

一些调查

我检查了react-window FixedSizeList(用于List)渲染方法。还有一些我自己还没有回答的问题:

    const memoizedChild = React.useMemo(() => {
        const memo = ({ index, style }: { index: number; style: any }): React.ReactElement => {
            return (
                <div style={style} key={index}>
                    <Tooltip title={t`stop` as string}>
                        <Button>lalla</Button>
                    </Tooltip>
                </div>
            );
        };
        memo.displayName = 'memo';
        return memo;
    }, []);

    return (
        <List height={758} width={625} itemSize={82} itemCount={filteredProfiles.length}>
            {memoizedChild}
        </List>
    );

而且看起来 React.createElement 根本不在乎记忆化的 children 组件,因此 React 一遍又一遍地挂载它。所以我偶然发现了这一点,想知道是 React.createElement 造成的还是用户代码(我的代码)写得不好。

问题

回答这些也会有帮助:

React.createElement(
  type, <- If this one is memoized, I mean
  [props],
  [...children]
)

Is it possible to resolve this tooltip flickering appearance issue with user code changes? What should be changed?

一切都很简单。当我小时候传递一个函数时,它会不断地被一遍又一遍地创建。所以解决方案是将子函数定义移出 render 方法,如下所示:

const MyButton: React.FC<{ style: any; index: number }> = ({ index, style }) => {
    return (
        <div style={style} key={index}>
            <Tooltip title={t`stop` as string}>
                <Button>lalla</Button>
            </Tooltip>
        </div>
    );
};

并像这样在渲染方法中使用它:

<List height={758} width={625} itemSize={82} itemCount={filteredProfiles.length}>
    {MyButton}
</List>

And this one especial curious, does React.createElement handles properly memoized type argument, according to its definition ...

createElement 不处理记忆,它只是创建一个反应元素。 Memoization 本身确保组件不会在没有任何更改的情况下被创建。