I'm trying to achieve a behaviour, when merely changed items of the list are being updated and rerendered with new data.
I wrote a component which is being updated when timer is off:
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>
);
And as a result, when timer is off, all items are rerendered, but none of them wasn't changed practically, which is resulting in flickering appearance of a tooltip:
I checked react-window
FixedSizeList
(which is used for List
) render method. And here is some questions which I didn't answer myself yet:
Why list itself is rerendered if all props are the same? Seems like this isn't optimized, so the component will be rerendered at any case, won't it? (render method sources)
And looking into render method, how props.children
are used, List
component uses React.createElement
to create a new element from passed-in props.children
. So I started to think that it's possible to memoize children and came up with this change to return result from function component:
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>
);
And it looks like React.createElement
doesn't give a damn about memoized children component and therefore React mounts it over and over again. So I stumbled upon this, wondering if it's React.createElement
to blame or user code (my code) is written badly.
These will be also helpful to have answered:
If previous answer is no, then, what changes should be made inside react-window
?
And this one especial curious, does React.createElement
handles properly memoized type
argument, according to its definition:
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?
All is pretty straight. When I was passing a function as a child, it was constantly being created over and over again. So the solution was to move child function definition out of render method like so:
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>
);
};
and use it in render method like so:
<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
doesn't handle memoization, it simply creates a react element. Memoization itself assures that the component will be not created if nothing changed.