Как применяется иммутабельность данных в React
Что проверяют
Понимаете ли вы механику: почему мутация состояния ломает обновление интерфейса, а не просто «так принято». Следом обычно дают код с push в массив из состояния и спрашивают, почему экран не обновился.
Как отвечать
React сравнивает старое и новое значение состояния через Object.is, то есть по ссылке. Если вы изменили объект и передали в setState тот же объект, React видит ту же ссылку и пропускает перерисовку. По ссылке же сравниваются пропсы в React.memo и зависимости useEffect, useMemo, useCallback. Иммутабельность делает эти дешёвые проверки честными: новая ссылка значит новые данные.
Как обновлять без мутаций:
- объекты:
{ ...user, name }, для вложенных данных копируется каждый уровень на пути к изменению; - массивы:
map,filter, spread вместоpushиsplice. Для сортировки есть неизменяющие методы ES2023:toSorted,toReversed,toSplicedиwith; - функциональное обновление:
setTodos(prev => [...prev, todo])берёт актуальное значение и не страдает от устаревшего замыкания; - Immer:
produceили хукuseImmerпозволяют писать как будто мутирующий код, а на выходе дают новый объект со структурным разделением. Redux Toolkit использует Immer внутриcreateSlice; structuredClone: глубокая копия, но дорогая, для обновлений состояния обычно избыточна.
Хорошо упомянуть React Compiler: он автоматически мемоизирует компоненты и опирается на то, что пропсы и состояние не мутируют. Мутация ломает его оптимизации так же, как ручной memo. А StrictMode в разработке дважды вызывает рендер и функции обновления, чтобы такие побочные эффекты всплыли раньше.
Где спотыкаются
Копируют только верхний уровень. { ...state } создаёт новый объект, но вложенный state.user.address остаётся той же ссылкой, и его мутация тихо портит и старое, и новое состояние.
Вызывают sort() или reverse() прямо в рендере на массиве из пропсов. Эти методы меняют исходный массив, и родитель внезапно видит пересортированные данные.
Путают иммутабельность с const. const запрещает переприсвоить переменную, но не мешает менять содержимое объекта.