> Как работают редьюсеры в Redux (JavaScript)
Уровень: senior · Роль: frontend · Категория: Технические вопросы
Компании: SmartWay
Стек: JavaScript
> Пример ответа
Короткий ответ
Редьюсер в Redux - это чистая функция (state, action) => newState, которая определяет, как состояние приложения изменяется в ответ на action. Она принимает текущее состояние и объект action, и возвращает новое состояние без мутации исходного. Редьюсеры должны быть детерминированными, без side-эффектов, и обычно объединяются через combineReducers для управления разными частями store.
Подробное объяснение
Редьюсеры - основа Redux, реализующая принцип однонаправленного потока данных. Каждый редьюсер отвечает за свой срез состояния (slice). Когда dispatch отправляет action, он проходит через все редьюсеры, и каждый решает, нужно ли обновить свою часть состояния.
Ключевые правила:
- Чистота: при одинаковых аргументах всегда возвращается одинаковый результат, без мутаций входных данных, API-вызовов или random.
- Неизменяемость: возвращается новый объект состояния, а не модифицируется старый. Используются spread-оператор,
Object.assignили Immer. - Дефолтный кейс: если action не обработан, возвращается текущее состояние как есть.
Типичная структура редьюсера - switch по action.type, хотя можно использовать if/else или lookup-таблицы. combineReducers генерирует корневой редьюсер, который делегирует обработку action дочерним редьюсерам по ключам.
Продвинутые паттерны:
- Нормализация состояния для вложенных данных.
- Использование
createReducerиз Redux Toolkit с builder callback, который автоматически защищает от мутаций через Immer. - Разделение редьюсеров по доменам (users, posts, ui) для масштабируемости.
На практике
В реальных проектах редьюсеры редко пишутся вручную - используется Redux Toolkit с createSlice. Это снижает boilerplate и исключает ошибки с мутациями. Важно следить за производительностью: избегать глубоких копий больших объектов, использовать селекторы с мемоизацией (Reselect).
Типичный workflow:
- Определяем начальное состояние для среза.
- Пишем редьюсер как набор обработчиков action.type.
- Комбинируем через
configureStore(RTK) илиcombineReducers. - В компонентах используем
useSelectorдля чтения иuseDispatchдля отправки action.
Пример кода
JAVASCRIPTimport { createSlice } from '@reduxjs/toolkit';const initialState = {items: [],loading: false,error: null,};const todosSlice = createSlice({name: 'todos',initialState,reducers: {addTodo: (state, action) => {state.items.push({ id: Date.now(), text: action.payload, completed: false });},toggleTodo: (state, action) => {const todo = state.items.find(item => item.id === action.payload);if (todo) todo.completed = !todo.completed;},removeTodo: (state, action) => {state.items = state.items.filter(item => item.id !== action.payload);},},});export const { addTodo, toggleTodo, removeTodo } = todosSlice.actions;export default todosSlice.reducer;
Как отвечать на собеседовании
На уровне senior важно не просто описать механику, а показать понимание trade-off: почему чистота критична для предсказуемости и тестирования, как избегать мутаций в больших проектах, когда стоит использовать нормализацию. Упомяни, что Redux Toolkit решает большинство проблем, но знание чистых редьюсеров необходимо для legacy-кода и глубокого понимания.
Структура ответа:
- Определение и принципы.
- Пример из практики с RTK.
- Продвинутые аспекты: композиция, производительность, тестирование.
- Сравнение с альтернативами (MobX, Zustand) - почему Redux выбирает редьюсеры.
Что проверяет интервьюер
- Понимание функционального программирования: чистота, неизменяемость, детерминизм.
- Умение проектировать состояние: как разбивать на срезы, избегать избыточности.
- Знание экосистемы: RTK, Immer, Reselect.
- Навыки отладки: как дебажить редьюсеры, что такое time-travel debugging.
- Оценка производительности: когда редьюсер становится узким местом.
Типичные ошибки
- Мутация состояния напрямую (например,
state.items.push()без Immer). - Side-эффекты в редьюсере (API-вызовы,
Math.random()). - Возврат undefined вместо state в дефолтном кейсе.
- Слишком большой редьюсер, который обрабатывает все action - нарушение single responsibility.
- Игнорирование начального состояния - приводит к ошибкам при инициализации.
- Использование глубоких копий для всего состояния вместо точечных обновлений.
> Похожие задачи по frontend
Каким методом промиса выполнить несколько параллельных запросов и получить результат каждого
Как работает Redux Saga
Как отслеживать события мыши на canvas во frontend
Каким методом промиса получить результат первого выполненного запроса
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью