Как предотвратить повторную визуализацию дочерних элементов внутри компонента List окна реакции

Проблема

Я пытаюсь добиться поведения, когда просто измененные элементы списка обновляются и перерисовываются с новыми данными.

Я написал компонент, который обновляется, когда таймер выключен:

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>
    );

И в результате при выключенном таймере все элементы перерисовываются, но ни один из них практически не менялся, что приводит к мерцанию всплывающей подсказки:

Как предотвратить повторную визуализацию дочерних элементов внутри компонента 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]
)
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
0
26
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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 не обрабатывает запоминание, он просто создает элемент реакции. Сама мемоизация гарантирует, что компонент не будет создан, если ничего не изменилось.

Другие вопросы по теме