Ответ
Reducer (редюсер) в Redux — это чистая функция, которая определяет, как состояние (state) приложения изменяется в ответ на отправленное действие (action). Это единственное место, где логика обновления состояния должна быть описана.
Сигнатура функции:
function reducer(previousState, action) {
// Вычисляем и возвращаем следующее состояние
return nextState;
}
Три фундаментальных принципа Reducer:
- Чистота: Не производит сайд-эффектов (вызовов API, мутаций).
- Иммутабельность: Не изменяет переданный
previousState. Вместо этого создаёт и возвращает новый объект состояния. - Детерминированность: Для одних и тех же входных
stateиactionвсегда возвращает одинаковыйnextState.
Практический пример из моего опыта: Допустим, у нас есть состояние для управления списком задач (todo list).
// Начальное состояние
const initialState = {
todos: [],
filter: 'SHOW_ALL'
};
// Reducer
function todoApp(state = initialState, action) {
switch (action.type) {
case 'ADD_TODO':
// ВАЖНО: Не мутируем старый массив, создаём новый
return {
...state, // Копируем все поля предыдущего состояния
todos: [
...state.todos, // Копируем старый массив todos
{ // Добавляем новый элемент
id: action.payload.id,
text: action.payload.text,
completed: false
}
]
};
case 'TOGGLE_TODO':
return {
...state,
todos: state.todos.map(todo =>
// Если это не тот todo, возвращаем как есть
todo.id !== action.payload.id ? todo :
// Иначе создаём новый объект todo с изменённым полем
{ ...todo, completed: !todo.completed }
)
};
case 'SET_FILTER':
return {
...state,
filter: action.payload.filter
};
// На действие по умолчанию возвращаем неизменённое состояние
default:
return state;
}
}
Почему это важно: Такая архитектура делает изменения состояния предсказуемыми и легко тестируемыми. Вы можете логировать каждое действие и состояние «до/после», что неоценимо при отладке сложного взаимодействия в приложении.
Ответ 18+ 🔞
А, редюсеры, ёпта! Ну это ж классика, как водка с огурцом. Слушай сюда, я тебе сейчас на пальцах объясню, что это за зверь такой, а то некоторые думают, что это какой-то рик-ролл для программистов.
Редюсер — это, блядь, священная корова в мире Redux. Представь себе самого принципиального бухгалтера в твоей жизни, который ведёт главную книгу. У него есть правило: никаких исправлений поверх старого. Хочешь что-то поменять? Бери новый чистый лист, переписывай всё заново, а старый — в архив. Вот этот бухгалтер и есть редюсер, чистая функция, ядрёна вошь.
Что он делает, этот чувак? Проще говоря, он сидит и ждёт. Ждёт, пока ему принесут два документа:
previousState— это как последняя версия баланса компании, состояние приложения на данный момент.action— это, сука, приказ сверху, бумажка с печатью, где написано «Добавить задачу» или «Пометить как выполненное».
И его работа — не накосячить. Три его главных заповеди, которые он нарушить не может, иначе его уволят к ебеням:
- Чистота, как у ангела. Никаких своих делишек! Не может он вдруг пойти и запрос на сервер отправить или время на компьютере поменять. Только бумажки, только хардкор.
- Иммутабельность, или «Руками не трогать!» Ему принесли старый баланс (
state). Он его НИ В КОЕМ СЛУЧАЕ НЕ ПЕРЕЧЁРКИВАЕТ. Он берёт чистый бланк и аккуратненько, буковка в буковку, переписывает всё заново, внося ту единственную поправку из приказа (action). Старый документ остаётся неприкосновенным. Это, блядь, основа основ, запомни как «Отче наш». - Детерминированность. Это значит, что если ты дашь ему один и тот же баланс и один и тот же приказ хоть сто раз — он сто раз выдаст тебе абсолютно одинаковый новый баланс. Никаких «ой, а сегодня пятница, я по-другому посчитал». Предсказуемость, блядь, наше всё.
Смотри, как это выглядит в жизни, на примере списка дел:
// Начальное состояние. Пусто, как твои карманы после зарплаты.
const initialState = {
todos: [],
filter: 'SHOW_ALL'
};
// Сам редюсер. Обрати внимание на switch-case — это его рабочий инструмент.
function todoApp(state = initialState, action) {
switch (action.type) {
// Кейс 1: Приказ "ДОБАВИТЬ_ЗАДАЧУ"
case 'ADD_TODO':
// ВАЖНО! Смотри, как он не трогает старый state.
// Он создаёт новый объект, разворачивая в него всё из старого (...state).
// Потом КОПИРУЕТ старый массив задач (...state.todos) и ДОБАВЛЯЕТ в конец новую.
// Никакого push'а! Только копия и новый элемент.
return {
...state,
todos: [
...state.todos,
{
id: action.payload.id,
text: action.payload.text,
completed: false
}
]
};
// Кейс 2: Приказ "ПЕРЕКЛЮЧИТЬ_ЗАДАЧУ"
case 'TOGGLE_TODO':
return {
...state,
// Опять копия! map проходит по старому массиву и для каждой задачи проверяет:
// Это та самая задача, которую нужно поменять? Если нет — возвращает её как есть.
// Если ДА — создаёт НОВЫЙ объект задачи, копируя старые поля и меняя одно.
todos: state.todos.map(todo =>
todo.id !== action.payload.id ? todo :
{ ...todo, completed: !todo.completed }
)
};
// Кейс 3: Приказ "УСТАНОВИТЬ_ФИЛЬТР" (показать все/только выполненные/только активные)
case 'SET_FILTER':
// Тут проще. Копируем state и просто меняем одно поле.
return {
...state,
filter: action.payload.filter
};
// А если принесли какую-то левую бумажку, которую он не понимает?
// Он пожимает плечами и возвращает state в том виде, в котором получил. Без изменений.
default:
return state;
}
}
И зачем весь этот цирк, спросишь ты? А затем, чувак, что это даёт тебе, разработчику, сверхспособности.
- Отладка — одно удовольствие. Ты можешь записывать (логгировать) каждый приказ (
action) и состояние «до» и «после». Как в детективе: было так, произошло это, стало этак. Нашёл косяк? Просто отмотай лог назад и посмотри, на каком шаге твой бухгалтер-редюсер накосячил. - Тестирование — раз плюнуть. Подсунул ему начальное состояние, подсунул тестовый приказ — получил результат. Никаких скрытых эффектов, никаких зависимостей от времени или базы данных. Всё чисто, как стерильная игла.
- Путешествие во времени (time-travel debugging). Это вообще магия. Поскольку у тебя сохраняется каждое состояние и каждый приказ, ты можешь буквально перематывать состояние приложения туда-сюда. Охуенно же!
Вот и вся философия. Не мутируй, копируй. Не делай сайд-эффектов, просто считай. Будь проще, как этот редюсер, и жизнь наладится. Ну, по крайней мере, жизнь твоего стейт-менеджмента.