如何防止在 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
)渲染方法。还有一些我自己还没有回答的问题:
如果所有属性都相同,为什么列表本身会被重新渲染?好像这没有优化,所以无论如何都会重新渲染组件,不是吗? (render method sources)
并查看渲染方法,如何使用 props.children
,List
组件使用 React.createElement
从 passed-in 创建新元素 props.children
。所以我开始认为可以记忆 children 并想出了这个对 return 的更改来自函数组件:
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-window
里面应该做哪些改动?
这个特别好奇,React.createElement
是否根据其定义正确处理记忆的 type
参数:
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 本身确保组件不会在没有任何更改的情况下被创建。
问题
我正在尝试实现一种行为,当仅更新列表中已更改的项目并使用新数据重新呈现时。
我写了一个组件,它在计时器关闭时正在更新:
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
)渲染方法。还有一些我自己还没有回答的问题:
如果所有属性都相同,为什么列表本身会被重新渲染?好像这没有优化,所以无论如何都会重新渲染组件,不是吗? (render method sources)
并查看渲染方法,如何使用
props.children
,List
组件使用React.createElement
从 passed-in 创建新元素props.children
。所以我开始认为可以记忆 children 并想出了这个对 return 的更改来自函数组件:
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-window
里面应该做哪些改动?这个特别好奇,
React.createElement
是否根据其定义正确处理记忆的type
参数:
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 本身确保组件不会在没有任何更改的情况下被创建。