@insighter
C#, React, JS

Как запретить React пересоздавать дочерние компоненты?

Пишу свой компонент для работы с табами. Табы в свою очередь тоже React-компоненты и генерируются динамически в цикле.
Использую стандартный подход: создается (через useState) состояние в которое записывается массив табов. Как только таб удаляется или добавляется новый, создается новый массив в котором добавлен/удален таб. Затем этот массив передается как новое состояние.

Все хорошо работает, но при удалении таба, Rect пересоздает все табы после удаленного, принимая их за новые объекты.

Как сказать фреймворку, что эти объекты уже созданы?

PS пробовал прописывать key (генерировал последовательные суррогатные ключи) не работает.
PPS при удалении таба, новый массив создают так:

let tabsNewList = tabs.slice();
tabsNewList.splice(tabIndex, 1);
...
...
setTabs(tabsNewList);
  • Вопрос задан
  • 118 просмотров
Решения вопроса 1
@insighter Автор вопроса
C#, React, JS
Ответ нашел сам.
При сравнении старого и нового DOM, React сравнивает поле key у существующего и нового объекта, если значения
полей совпадают, то новый объект отбрасывается, иначе старый объект будет уничтожен и полностью замещен новым. Конечно же сравнение ключей лишь малая часть общего алгоритма согласования.

Моем случае, компоненты, которые отображаются в табах могут быть разных типов, а чаще всего только так и есть.
Поэтому React не использует сравнение через key и удаляет оставшиеся закладки (хотя! почему то, если создать
вкладки одного типа, они все равно удалятся
)

Решение найдено в использовании компонента Fragment с суррогатным ключом key

Генерация ключа:
const [keyGenValue, setKeyGenValue] = useState(1);
    ...
    // генерим новое значение при открытии новой вкладки
    setKeyGenValue(() => {
        return keyGenValue + 1;
    });


Генерация рендера:

<div className='workspace'>
    {views.map(
        (view, index) =>
        <Fragment key={view.key}>
            <div hidden={view !== selectedView}>
                    <h4>{view.caption}</h4>
                    <div>{buildView(view.name)}</div>
            </div>
        </Fragment>
    )}
</div>
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы