Какие плюсы и минусы иммутабельности данных
Что проверяют
Понимаете ли вы, почему React и Redux требуют не мутировать состояние, и знаете ли, чем за это приходится платить. Следом почти всегда просят обновить вложенное поле без мутации или спрашивают про Immer.
Как отвечать
Начните с механики: React сравнивает состояние и пропсы по ссылке через Object.is. Если вы изменили объект на месте и передали его же в setState, ссылка прежняя, компонент может не перерисоваться, а React.memo, useMemo и useEffect с зависимостями перестанут видеть изменения. Отсюда плюсы:
- дешёвое сравнение: проверить
prev !== nextбыстрее, чем обходить объект целиком, на этом держатся мемоизация и селекторы; - предсказуемость: данные не меняются из чужого кода за вашей спиной, источник бага искать проще;
- история состояний: undo/redo и time-travel в Redux DevTools получаются почти даром, старые версии просто остаются в памяти;
- структурное разделение: новая версия переиспользует неизменённые ветки, копируется только путь до изменённого поля.
Минусы тоже конкретные:
- аллокации: каждое изменение создаёт новые объекты, в горячих циклах (canvas, анимации, большие таблицы) это нагрузка на сборщик мусора;
- многословность: обновление поля на четвёртом уровне вложенности через spread читается плохо, поэтому в Redux Toolkit встроен Immer, где вы пишете «мутирующий» код по черновику;
- ложное чувство защиты:
constиObject.freezeне делают данные глубоко неизменяемыми.
Упомяните методы массивов, которые возвращают копию: toSorted, toReversed, toSpliced, with.
Где спотыкаются
Путают const с иммутабельностью. const запрещает переприсвоить переменную, но arr.push() на ней работает.
Считают spread глубокой копией. {...state} копирует только верхний уровень, вложенный объект остаётся общим, и его мутация ломает сравнение. Для глубокой копии есть structuredClone, но в стейте она обычно не нужна.
Вызывают arr.sort() прямо на массиве из пропсов или стейта. Метод сортирует на месте, и это мутация чужих данных.