Я пытаюсь добиться поведения, когда просто измененные элементы списка обновляются и перерисовываются с новыми данными.
Я написал компонент, который обновляется, когда таймер выключен:
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>
);
И в результате при выключенном таймере все элементы перерисовываются, но ни один из них практически не менялся, что приводит к мерцанию всплывающей подсказки:
Я проверил react-windowFixedSizeList (который используется для List) метода рендеринга. И вот несколько вопросов, на которые я сам еще не ответил:
Почему сам список перерисовывается, если все реквизиты одинаковы? Похоже, это не оптимизировано, поэтому компонент будет перерендерен в любом случае, не так ли? (исходники метода рендеринга)
И глядя на метод рендеринга, как используются props.children, компонент List использует React.createElement для создания нового элемента из переданного props.children. Поэтому я начал думать, что можно запоминать дочерние элементы, и придумал это изменение, чтобы возвращать результат из функционального компонента:
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 наплевать на мемоизированный дочерний компонент, и поэтому 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?
Все довольно прямо. Когда я в детстве передавал функцию, она постоянно создавалась снова и снова. Таким образом, решение состояло в том, чтобы переместить определение дочерней функции из метода рендеринга следующим образом:
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 не обрабатывает запоминание, он просто создает элемент реакции. Сама мемоизация гарантирует, что компонент не будет создан, если ничего не изменилось.