Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Архитектура Redux: как это работает
Redux - это предсказуемый контейнер состояния для приложений JavaScript. Рассмотрим его архитектуру и внутреннее устройство.
1. Три ключевых концепции Redux
Redux строится на трёх основных идеях:
// 1. STORE - единое хранилище всего состояния приложения
const store = createStore(reducer);
// 2. ACTION - объект, описывающий, что произошло
const action = {
type: "INCREMENT",
payload: 5
};
// 3. REDUCER - чистая функция, которая преобразует состояние
const reducer = (state = 0, action) => {
if (action.type === "INCREMENT") {
return state + action.payload;
}
return state;
};
2. Упрощённая реализация Redux
Вот как примерно работает Redux на самом низком уровне:
// Минимальная реализация Redux
function createStore(reducer) {
let state;
let listeners = [];
// Получить текущее состояние
function getState() {
return state;
}
// Отправить действие
function dispatch(action) {
// Вызвать reducer с текущим состоянием и действием
state = reducer(state, action);
// Уведомить всех слушателей об изменении
listeners.forEach((listener) => listener());
}
// Подписаться на изменения
function subscribe(listener) {
listeners.push(listener);
// Возвращаем функцию для отписки
return () => {
listeners = listeners.filter((l) => l !== listener);
};
}
// Инициализируем состояние
dispatch({ type: "@@INIT" });
return { getState, dispatch, subscribe };
}
// Использование
const counterReducer = (state = 0, action) => {
switch (action.type) {
case "INCREMENT":
return state + 1;
case "DECREMENT":
return state - 1;
default:
return state;
}
};
const store = createStore(counterReducer);
store.subscribe(() => {
console.log("Состояние изменилось:", store.getState());
});
store.dispatch({ type: "INCREMENT" }); // Выведет 1
store.dispatch({ type: "INCREMENT" }); // Выведет 2
store.dispatch({ type: "DECREMENT" }); // Выведет 1
3. Reducer и его правила
Reducer - это чистая функция, которая следует определённым правилам:
// Правильный reducer (чистая функция)
const counterReducer = (state = 0, action) => {
switch (action.type) {
case "INCREMENT":
// Возвращаем новое значение
return state + 1;
case "DECREMENT":
return state - 1;
default:
return state;
}
};
// Неправильный reducer (побочные эффекты)
const wrongReducer = (state = 0, action) => {
// НЕПРАВИЛЬНО: мутирует состояние
state.count++;
return state;
// НЕПРАВИЛЬНО: асинхронные операции
fetch("/api/data").then((res) => res.json());
// НЕПРАВИЛЬНО: вызов функций с побочными эффектами
console.log("Действие:", action);
};
// Правильный способ обновления объектов
const userReducer = (state = {}, action) => {
switch (action.type) {
case "SET_NAME":
// Создаём новый объект, не мутируя старый
return { ...state, name: action.payload };
case "SET_AGE":
return { ...state, age: action.payload };
default:
return state;
}
};
4. Middleware в Redux
Middleware позволяет расширить функциональность dispatch:
// Структура middleware
const middleware = (store) => (next) => (action) => {
console.log("Действие:", action);
const result = next(action); // Передаём действие дальше
console.log("Новое состояние:", store.getState());
return result;
};
// Примеры middleware
const loggerMiddleware = (store) => (next) => (action) => {
console.log("Перед:", store.getState());
const result = next(action);
console.log("После:", store.getState());
return result;
};
const crashReporterMiddleware = (store) => (next) => (action) => {
try {
return next(action);
} catch (error) {
console.error("Ошибка:", error);
throw error;
}
};
// Применение middleware
function applyMiddleware(...middlewares) {
return (createStore) => {
return (reducer, preloadedState) => {
const store = createStore(reducer, preloadedState);
let dispatch = store.dispatch;
const middlewareAPI = {
getState: store.getState,
dispatch: (action) => dispatch(action)
};
const chain = middlewares.map((m) => m(middlewareAPI));
dispatch = chain.reduce(
(composed, m) => (action) => m(composed(action)),
store.dispatch
);
return { ...store, dispatch };
};
};
}
5. Combineducers - объединение reducers
const counterReducer = (state = 0, action) => {
if (action.type === "INCREMENT") return state + 1;
return state;
};
const userReducer = (state = { name: "" }, action) => {
if (action.type === "SET_NAME") {
return { ...state, name: action.payload };
}
return state;
};
// Упрощённая реализация combineReducers
function combineReducers(reducers) {
return (state = {}, action) => {
const newState = {};
for (const key in reducers) {
newState[key] = reducers[key](state[key], action);
}
return newState;
};
}
const rootReducer = combineReducers({
counter: counterReducer,
user: userReducer
});
const store = createStore(rootReducer);
// store.getState() => { counter: 0, user: { name: "" } }
6. Селекторы для получения данных
// Селектор - функция для получения части состояния
const selectCounter = (state) => state.counter;
const selectUserName = (state) => state.user.name;
// Мемоизированный селектор (для оптимизации)
const selectVisibleTodos = (() => {
let lastState = null;
let lastResult = null;
return (state) => {
if (lastState !== state.todos) {
lastState = state.todos;
lastResult = state.todos.filter((t) => !t.completed);
}
return lastResult;
};
})();
7. Данные flow в Redux
// Цикл Redux
// 1. Компонент диспатчит действие
dispatch({ type: "INCREMENT" });
// 2. Действие проходит через middleware
// (если оно есть)
// 3. Reducer получает действие и текущее состояние
const newState = reducer(state, action);
// 4. Store обновляется новым состоянием
state = newState;
// 5. Уведомляются все подписчики
listeners.forEach((listener) => listener());
// 6. Компонент получает новое состояние и перерисовывается
const component = (state) => <div>{state.counter}</div>;
8. Redux Devtools Integration
const store = createStore(
rootReducer,
window.__REDUX_DEVTOOLS_EXTENSION__ &&
window.__REDUX_DEVTOOLS_EXTENSION__()
);
// Это позволяет использовать Redux DevTools для:
// - Time-travel debugging
// - Просмотра истории действий
// - Воспроизведения действий
// - Экспорта/импорта состояния
9. Сравнение с Flux
// Redux: одно хранилище, чистые reducers
const store = createStore(reducer);
// Flux: множество хранилищ, вызов методов напрямую
class Store {
update(action) {
// Логика изменения состояния
}
}
10. Ключевые преимущества архитектуры Redux
- Предсказуемость: чистые функции и одно состояние
- Отладка: time-travel, логирование действий
- Тестируемость: reducers - это просто функции
- Масштабируемость: хорошо для больших приложений
- Экосистема: множество middleware и инструментов
- DevTools: мощные средства для разработки
Мой практический опыт: Redux иногда кажется verbose для простых приложений, но его архитектура становится преимуществом на больших проектах. Главное понять, что это функциональное программирование в действии - чистые функции, неизменяемость данных и единая точка истины для состояния.