Видеоуроки, интерактивный редактор и сохранение прогресса — бесплатно, сразу после входа.
ВойтиСоздать аккаунт — бесплатноЗакончили урок?
Войдите, чтобы отмечать прогресс
В этом решении контекст разделён на два (состояние и действие), value провайдеров стабилизированы через useMemo, а строка списка вынесена в мемоизированный компонент по пропсам. При смене выбора перерисовываются только две строки — бывшая и новая активная.
Один контекст хранит только выбранный id (меняется при клике), второй — только функцию setSelectedId (ссылка стабильна). Компонент, подписанный только на контекст с сеттером, не перерисовывается при смене selectedId, потому что value этого провайдера не меняется.
Строка не читает контекст — она получает letter, isActive и onSelect пропсами. React.memo не даёт перерисовывать компонент, если пропсы не изменились. При смене выбора меняется только isActive у двух строк (у той, что перестала быть активной, и у новой активной); у остальных 98 пропсы те же, memo пропускает ре-рендер.
Обёртка подписана на оба контекста и передаёт в LetterRow только нужное: активна ли строка и колбэк выбора. setSelectedId стабилен (useMemo с пустым массивом зависимостей в App), поэтому при смене selectedId перерисовывается только LetterRowWithContext — а LetterRow внутри перерисуется лишь если изменились пропсы (letter тот же, onSelect тот же, меняется только isActive у двух строк).
stateValue — примитив selectedId, обёрнутый в useMemo, чтобы при том же selectedId ссылка не менялась (здесь по сути просто selectedId). actionsValue — setSelectedId в useMemo с []: ссылка на функцию одна и та же на всё время жизни. В списке рендерится LetterRowWithContext, а не LetterRow напрямую — контекст читает обёртка, тяжёлая разметка в мемоизированной строке. Итог: при клике перерисовываются только две строки вместо ста.