Зачем нужен иммутабельный стейт?

🎯 Зачем спрашивают
  • Понимание принципов архитектуры Redux. Знает ли кандидат, что Redux основан на иммутабельности и чистых функциях.
  • Осознанность причин, а не заученность практик. Может ли объяснить зачем нужен иммутабельный state, а не просто «так написано в доках».
  • Уровень инженерного мышления. Понимает ли, как иммутабельность связана с производительностью (O(1) сравнение по ссылке), отладкой и тестируемостью.
  • Знание современных инструментов. Знает ли про то, как Immer и Redux Toolkit скрывают иммутабельность, сохраняя её преимущества.
  • Умение объяснять сложные вещи просто. Этот вопрос часто проверяет не только знания, но и способность чётко формулировать мысль.
 
📝 Ответ
Коротко:
Иммутабельный state в Redux нужен, чтобы библиотека могла сравнить два объекта и определить, что состояние изменилось.
Библиотеки-обёртки (React-Redux) сравнивают объекты по ссылке, чтобы определить, изменилось ли состояние и нужно ли перерисовать компонент. Поэтому важно создавать новый объект, а не мутировать старый.
 
function counterReducer(state = { count: 0 }, action) { switch (action.type) { case 'INCREMENT': return { ...state, count: state.count + 1 }; default: return state; } }
Reducer, возвращающий новый объект
 
Подробнее:
Иммутабельный стейт в Redux — это один из базовых принципов его архитектуры. Данный принцип позволяет:
  • эффективнее для производительности сравнить новое и старое состояния
  • сделать отладку более наглядной
  • упростить тестирование
 
Сравнение состояний
Redux сравнивает объекты state посредством сравнение ссылок. Если state иммутабельный, это сравнение суперэффективно:
if (prevState !== nextState) { // состояние изменилось — перерисовываем }
Алгоритмическая сложность такого сравнения — O(1).
 
Есть и другие способы сравнить в JS объекты:
  • мануальное сравнение (shallow equal/deep equal)
  • JSON.stringify
 
Способ
❌ Минусы
shallow equal
Стор может быть любой вложенности. Я, как разработчик библиотеки, буду вынужден ограничивать пользователей
deep equal
Если стор обладает большой вложенностью, то сравнивать state при каждом изменении будет затратно по производительности
JSON.stringify
Порядок свойств влияет на результат Не сериализуются некоторые типы данных
Предсказуемость и отладка
Иммутабельность позволяет Redux хранить историю всех состояний. Каждый объект state — snapshot. Иммутабельность позволяет инструментам (например, Redux DevTools) хранить историю состояний, потому что каждое новое состояние — отдельный объект, давая возможность:
  • перемещаться назад/вперёд во времени (time travel debugging);
  • показывать, какие actions привели к какому состоянию.
Это работает, потому что каждое новое состояние — новый объект, а старое состояние остаётся нетронутым.
Упрощение тестирования
Чистые функции + иммутабельность = простые тесты.
Редьюсер можно протестировать без моков или контекста приложения:
expect(counterReducer({ count: 1 }, { type: 'INCREMENT' })) .toEqual({ count: 2 });
 
⚠️
В RTK же по-другому…
RTK под капотом использует библиотеку Immer. Immer перехватывает все изменения, которые ты «как будто» делаешь напрямую в state, и создаёт его неизменяемую копию автоматически.
const counterSlice = createSlice({ name: 'counter', initialState: { value: 0 }, reducers: { increment(state) { state.value += 1; // можно мутировать! } } });
На самом деле ничего не мутируется напрямую — Immer создаёт draft (черновик состояния), отслеживает все изменения и возвращает новый объект, не трогая старый state.
 
⚖️ Компромиссы
✅ Плюсы
❌ Минусы
Простая проверка изменений O(1)
Повышенный расход памяти (особенно при больших state)
Предсказуемость, лёгкий дебаг и тестирование.
Возможна путаница у новичков, если RTK "прячет" иммутабельность под капотом.
Если не использовать immer.js и/или RTK, то синтаксис будет казаться избыточным
 
🔎 Встречные вопросы
  • Какие в JavaScript есть возможности сравнить объекты?
  • Почему в Redux важно не мутировать state, но в RTK можно?
  • Что произойдёт, если изменить state по ссылке в reducer?
  • Почему React-Redux не перерисует компонент, если state мутирован?
  • Как работает Immer под капотом?
 
🚩 Красные флаги
  • Иммутабельность нужна, чтобы нельзя было испортить данные (частично верно, но не ключевая причина.
  • Потому что в Redux так написано в доках.
  • Чтобы было безопаснее (расплывчато, без понимания сравнения ссылок).
 
🛠 Практика
 
📚 Источники / ссылки