Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Зачем Redux организовано на экшены, хранилища и редьюсеры
Это архитектурное разделение ответственности для управления состоянием. Redux следует принципам Flux и функционального программирования.
Redux архитектура
┌───────────────┐
│ React View │
└───────┬───────┘
│
│ Dispatch Action
v
┌───────────────┐
│ Actions │ {type: 'USER_LOGIN', payload}
└───────┬───────┘
│
│ Process
v
┌───────────────┐
│ Reducers │ (state, action) => newState
└───────┬───────┘
│
│ Update
v
┌───────────────┐
│ Store │ {users: [], auth: {}}
└───────┬───────┘
│
│ Subscribe
v
┌───────────────┐
│ Components │ re-render
└───────────────┘
1. Actions (описывают ЧТО произошло)
// Action = объект с типом и данными
const loginAction = {
type: 'USER_LOGIN',
payload: { userId: 123, name: 'John' }
};
// Action Creator (функция для создания action)
const login = (userId, name) => ({
type: 'USER_LOGIN',
payload: { userId, name }
});
// Использование
dispatch(login(123, 'John'));
Зачем отдельно:
- Четкая структура (всегда type + payload)
- Легко логировать события
- Можно отладить любое действие
- Тестировать просто (чистые функции)
2. Reducers (описывают КАК изменить состояние)
// Reducer = чистая функция
// (state, action) => newState
const initialState = {
user: null,
isLoading: false,
error: null
};
const authReducer = (state = initialState, action) => {
switch (action.type) {
case 'USER_LOGIN':
return {
...state,
user: action.payload,
error: null
};
case 'USER_LOGOUT':
return {
...state,
user: null
};
default:
return state;
}
};
Зачем отдельно:
- Чистые функции (без побочных эффектов)
- Легко тестировать (input -> output)
- Предсказуемо (один action -> один результат)
- Легко отладить (каждый шаг видно)
3. Store (единое хранилище состояния)
import { createStore } from 'redux';
const store = createStore(authReducer);
// Получить состояние
console.log(store.getState());
// Подписаться на изменения
store.subscribe(() => {
console.log('Состояние изменилось:', store.getState());
});
// Отправить action
store.dispatch(login(123, 'John'));
Зачем отдельно:
- Единое место истины (одно состояние)
- Все компоненты видят одно состояние
- Нет дублирования данных
- Легко синхронизировать
Полный цикл Redux
// 1. Action (что произошло)
const action = {
type: 'INCREMENT_COUNTER',
payload: 1
};
// 2. Reducer (как изменить)
const counterReducer = (state = 0, action) => {
if (action.type === 'INCREMENT_COUNTER') {
return state + action.payload;
}
return state;
};
// 3. Store (где хранится)
const store = createStore(counterReducer);
// 4. Dispatch (отправить action)
store.dispatch(action);
// 5. Новое состояние
console.log(store.getState()); // 1
Зачем разделение
Без Redux (ad-hoc管理)
// Состояние повсюду
let user = null;
let isLoading = false;
let error = null;
// Функции изменяют глобальное состояние
function login(userId) {
isLoading = true;
fetchUser(userId).then(data => {
user = data; // Изменение
isLoading = false; // Изменение
});
}
// Проблемы:
// - Не понятно, кто изменил состояние
// - Сложно отследить изменения
// - Сложно тестировать
// - Race conditions
С Redux (структурированно)
// Actions - ясно ЧТО произошло
const LOGIN_START = 'LOGIN_START';
const LOGIN_SUCCESS = 'LOGIN_SUCCESS';
const LOGIN_FAILURE = 'LOGIN_FAILURE';
// Reducers - ясно КАК изменить
const authReducer = (state, action) => {
switch (action.type) {
case LOGIN_START:
return {...state, isLoading: true};
case LOGIN_SUCCESS:
return {...state, user: action.payload, isLoading: false};
case LOGIN_FAILURE:
return {...state, error: action.payload, isLoading: false};
}
};
// Thunk middleware для async
const login = (userId) => (dispatch) => {
dispatch({type: LOGIN_START});
fetchUser(userId)
.then(data => dispatch({type: LOGIN_SUCCESS, payload: data}))
.catch(err => dispatch({type: LOGIN_FAILURE, payload: err}));
};
// Преимущества:
// - Все изменения отслеживаемы
// - Легко отладить (DevTools)
// - Чистые функции (тестируемо)
// - Нет race conditions
Middleware (для async операций)
// Thunk для async действий
const thunk = store => next => action => {
if (typeof action === 'function') {
return action(store.dispatch, store.getState);
}
return next(action);
};
// Использование
const fetchUser = (id) => async (dispatch) => {
dispatch({type: 'LOADING'});
try {
const data = await fetch(`/api/users/${id}`).then(r => r.json());
dispatch({type: 'SUCCESS', payload: data});
} catch (e) {
dispatch({type: 'ERROR', payload: e});
}
};
Несколько reducers (combineReducers)
const authReducer = (state = {}, action) => {...};
const counterReducer = (state = 0, action) => {...};
const postsReducer = (state = [], action) => {...};
const rootReducer = combineReducers({
auth: authReducer,
counter: counterReducer,
posts: postsReducer
});
const store = createStore(rootReducer);
// State структура
store.getState(); // {auth: {}, counter: 0, posts: []}
Redux DevTools (отладка)
// Видишь все actions в порядке
// Можешь перемотать любое действие
// Видишь, как изменилось состояние
// Экспортировать/импортировать состояние
const store = createStore(
rootReducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
Когда Redux нужен
✓ Много компонентов с общим состоянием
✓ Нужна отладка (DevTools)
✓ Сложная логика изменения состояния
✓ Нужно сохранить историю действий
✓ Коллаборативная разработка
✗ Простое приложение (используй useState)
✗ Локальное состояние компонента
Альтернативы
// Context API (проще, но менее мощно)
const StoreContext = createContext();
// Zustand (проще Redux)
const useStore = create((set) => ({
user: null,
setUser: (u) => set({user: u})
}));
// MobX (реактивное, но сложнее)
class Store {
@observable user = null;
}
Заключение
Redux разделен на:
- Actions - описывают ЧТО произошло
- Reducers - описывают КАК изменить состояние
- Store - единое хранилище истины
Это разделение дает:
- Предсказуемость
- Отслеживаемость
- Тестируемость
- Отладку
Оно следует функциональному программированию и функции чистых (pure functions).