Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Reducer в Redux
Reducer — это чистая функция (pure function), которая принимает два аргумента: текущее состояние (state) и действие (action), а затем возвращает новое состояние. Это сердце Redux архитектуры.
Определение
// Сигнатура reducer:
(previousState, action) => newState
// Пример:
function counterReducer(state = 0, action) {
switch (action.type) {
case "INCREMENT":
return state + 1;
case "DECREMENT":
return state - 1;
default:
return state;
}
}
Основные принципы Reducer
1. Должен быть чистой функцией (Pure Function)
Это значит:
- Одинаковый вход → одинаковый выход
- Нет побочных эффектов
- Не мутирует входные аргументы
- Не выполняет асинхронные операции
// ❌ НЕПРАВИЛЬНО — reducer мутирует state
function badReducer(state, action) {
if (action.type === "SET_NAME") {
state.user.name = action.payload; // мутация!
return state;
}
return state;
}
// ✅ ПРАВИЛЬНО — создаём новый объект
function goodReducer(state, action) {
if (action.type === "SET_NAME") {
return {
...state,
user: {
...state.user,
name: action.payload
}
};
}
return state;
}
2. Должен иметь начальное состояние
// Старый стиль (ES5)
function todoReducer(state, action) {
if (state === undefined) {
state = [];
}
// ...
}
// Современный стиль (с параметром по умолчанию)
function todoReducer(state = [], action) {
switch (action.type) {
case "ADD_TODO":
return [...state, action.payload];
default:
return state;
}
}
Полный пример: Todo Reducer
const initialState = {
todos: [],
filter: "all" // all, active, completed
};
function todoReducer(state = initialState, action) {
switch (action.type) {
// Добавление todo
case "ADD_TODO":
return {
...state,
todos: [
...state.todos,
{
id: Date.now(),
text: action.payload,
completed: false
}
]
};
// Удаление todo
case "DELETE_TODO":
return {
...state,
todos: state.todos.filter(todo => todo.id !== action.payload)
};
// Переключение статуса todo
case "TOGGLE_TODO":
return {
...state,
todos: state.todos.map(todo =>
todo.id === action.payload
? {...todo, completed: !todo.completed}
: todo
)
};
// Установка фильтра
case "SET_FILTER":
return {
...state,
filter: action.payload
};
default:
return state;
}
}
Как Reducer работает в Redux
import { createStore } from redux;
// Создаём store с reducer
const store = createStore(todoReducer);
// Отправляем действие
store.dispatch({
type: "ADD_TODO",
payload: "Learn Redux"
});
// Reducer обрабатывает действие и обновляет состояние
// Старое состояние: { todos: [], filter: "all" }
// Действие: { type: "ADD_TODO", payload: "Learn Redux" }
// Новое состояние: {
// todos: [{id: 1234, text: "Learn Redux", completed: false}],
// filter: "all"
// }
// Получаем новое состояние
const state = store.getState();
console.log(state);
Combine Reducers (несколько reducers)
const userReducer = (state = {name: "", role: "user"}, action) => {
switch (action.type) {
case "SET_USER":
return action.payload;
default:
return state;
}
};
const themeReducer = (state = "light", action) => {
switch (action.type) {
case "TOGGLE_THEME":
return state === "light" ? "dark" : "light";
default:
return state;
}
};
// Объединяем reducers
const rootReducer = combineReducers({
user: userReducer,
theme: themeReducer
});
const store = createStore(rootReducer);
// Структура состояния:
// {
// user: {name: "", role: "user"},
// theme: "light"
// }
Reducer с payload (расширенный пример)
const initialState = {
items: [],
loading: false,
error: null
};
function itemsReducer(state = initialState, action) {
switch (action.type) {
case "FETCH_START":
return {
...state,
loading: true,
error: null
};
case "FETCH_SUCCESS":
return {
...state,
items: action.payload,
loading: false
};
case "FETCH_ERROR":
return {
...state,
loading: false,
error: action.payload
};
case "ADD_ITEM":
return {
...state,
items: [...state.items, action.payload]
};
default:
return state;
}
}
Действия (Actions) vs Reducer
// Action — просто объект с информацией что произошло
const action = {
type: "ADD_TODO",
payload: "Buy milk" // данные
};
// Reducer — функция, которая определяет КАК изменить состояние
function reducer(state, action) {
if (action.type === "ADD_TODO") {
return {
...state,
todos: [...state.todos, action.payload]
};
}
return state;
}
Типичная ошибка: прямое изменение состояния
// ❌ НЕПРАВИЛЬНО
function badReducer(state = {count: 0}, action) {
if (action.type === "INCREMENT") {
state.count++; // МУТАЦИЯ!
return state;
}
return state;
}
// ✅ ПРАВИЛЬНО
function goodReducer(state = {count: 0}, action) {
if (action.type === "INCREMENT") {
return {
...state,
count: state.count + 1
};
}
return state;
}
// Почему это важно?
// Redux использует === для проверки изменений
// Если вернуть тот же объект, Redux не обнаружит изменение!
const oldState = {count: 0};
const newState = badReducer(oldState, {type: "INCREMENT"});
console.log(oldState === newState); // true (один и тот же объект!)
console.log(oldState.count); // 1 (изменилось!)
Reducer с сложной логикой
function cartReducer(state = {items: [], total: 0}, action) {
switch (action.type) {
case "ADD_TO_CART":
const newItems = [...state.items, action.payload];
const newTotal = newItems.reduce((sum, item) => sum + item.price, 0);
return {
items: newItems,
total: newTotal
};
case "REMOVE_FROM_CART":
const filteredItems = state.items.filter(
item => item.id !== action.payload
);
const updatedTotal = filteredItems.reduce(
(sum, item) => sum + item.price,
0
);
return {
items: filteredItems,
total: updatedTotal
};
default:
return state;
}
}
Использование в React компоненте (Redux Hooks)
import { useSelector, useDispatch } from react-redux;
function TodoApp() {
const todos = useSelector(state => state.todos);
const dispatch = useDispatch();
const addTodo = (text) => {
dispatch({
type: "ADD_TODO",
payload: text
});
};
return (
<div>
{todos.map(todo => (
<div key={todo.id}>{todo.text}</div>
))}
<button onClick={() => addTodo("New task")}>
Add Todo
</button>
</div>
);
}
Резюме: Что делает Reducer?
- Принимает текущее состояние и действие (action)
- Вычисляет новое состояние на основе типа действия
- Возвращает новое состояние (никогда не мутирует старое)
- Является чистой функцией — предсказуемой и без побочных эффектов
- Обновляет Redux store, который уведомляет все подписанные компоненты
Аналогия: Если dispatch — это отправка письма (action), то reducer — это почтальон, который на основе содержания письма решает, как изменить содержимое шкафа (state).