← Назад к вопросам

Как использовать Redux Flow?

2.0 Middle🔥 181 комментариев
#State Management

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как использовать Redux Flow

Что такое Redux

Redux — это библиотека для управления состоянием приложения (state management). Она использует unidirectional data flow — однонаправленный поток данных.

Redux Flow: Однонаправленный поток

UI (View)
  |
  | dispatch(action)
  v
Action { type, payload }
  |
  | отправляется в
  v
Reducer (current state, action) -> new state
  |
  | обновляет
  v
Store (központalizované состояние)
  |
  | notify subscribers
  v
UI (View) переренде с новым state

Ключевые компоненты Redux

1. Action — объект, описывающий, что произошло

// Simple action
const incrementAction = {
  type: "INCREMENT",
  payload: 1
};

// Action creator (функция для создания action)
const increment = (amount) => ({
  type: "INCREMENT",
  payload: amount
});

const decrement = (amount) => ({
  type: "DECREMENT",
  payload: amount
});

2. Reducer — чистая функция, которая преобразует состояние

// Reducer: (prevState, action) -> newState
const counterReducer = (state = 0, action) => {
  switch (action.type) {
    case "INCREMENT":
      return state + action.payload;
    case "DECREMENT":
      return state - action.payload;
    default:
      return state;
  }
};

// Правила для reducers:
// 1. Должен быть чистой функцией (no side effects)
// 2. Никогда не мутировать state напрямую
// 3. Всегда возвращать новый state

3. Store — централизованное хранилище состояния

const { createStore } = require("redux");

const store = createStore(counterReducer);

// Методы Store:
store.getState();        // Получить текущее состояние
store.dispatch(action);  // Отправить action
store.subscribe(cb);     // Подписаться на изменения

Полный пример: Counter приложение

const { createStore } = require("redux");

// 1. Action creators
const increment = (amount = 1) => ({
  type: "INCREMENT",
  payload: amount
});

const decrement = (amount = 1) => ({
  type: "DECREMENT",
  payload: amount
});

const reset = () => ({
  type: "RESET"
});

// 2. Reducer
const counterReducer = (state = 0, action) => {
  switch (action.type) {
    case "INCREMENT":
      return state + action.payload;
    case "DECREMENT":
      return state - action.payload;
    case "RESET":
      return 0;
    default:
      return state;
  }
};

// 3. Create Store
const store = createStore(counterReducer);

// 4. Subscribe to changes
store.subscribe(() => {
  console.log("State changed:", store.getState());
});

// 5. Dispatch actions
store.dispatch(increment(5));  // State: 5
store.dispatch(increment(3));  // State: 8
store.dispatch(decrement(2));  // State: 6
store.dispatch(reset());       // State: 0

Redux с React

import { createStore } from "redux";
import { useSelector, useDispatch } from "react-redux";

// 1. Reducer
const initialState = {
  count: 0,
  user: null,
  loading: false
};

const appReducer = (state = initialState, action) => {
  switch (action.type) {
    case "INCREMENT":
      return { ...state, count: state.count + 1 };
    case "DECREMENT":
      return { ...state, count: state.count - 1 };
    case "SET_USER":
      return { ...state, user: action.payload };
    case "SET_LOADING":
      return { ...state, loading: action.payload };
    default:
      return state;
  }
};

// 2. Create store
const store = createStore(appReducer);

// 3. React компонент
function Counter() {
  // useSelector — получить данные из store
  const count = useSelector(state => state.count);
  const user = useSelector(state => state.user);
  
  // useDispatch — отправить action
  const dispatch = useDispatch();

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => dispatch({ type: "INCREMENT" })}>
        +
      </button>
      <button onClick={() => dispatch({ type: "DECREMENT" })}>
        -
      </button>
    </div>
  );
}

// 4. Wrap app with Provider
import { Provider } from "react-redux";

function App() {
  return (
    <Provider store={store}>
      <Counter />
    </Provider>
  );
}

Combinining Reducers (множественные reducers)

import { createStore, combineReducers } from "redux";

// Отдельные reducers для каждой части state
const counterReducer = (state = 0, action) => {
  switch (action.type) {
    case "INCREMENT":
      return state + 1;
    case "DECREMENT":
      return state - 1;
    default:
      return state;
  }
};

const userReducer = (state = null, action) => {
  switch (action.type) {
    case "SET_USER":
      return action.payload;
    case "LOGOUT":
      return null;
    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({
  counter: counterReducer,
  user: userReducer,
  theme: themeReducer
});

const store = createStore(rootReducer);

// State будет иметь структуру:
// {
//   counter: 0,
//   user: null,
//   theme: "light"
// }

// Использование в компонентах
const count = useSelector(state => state.counter);
const user = useSelector(state => state.user);
const theme = useSelector(state => state.theme);

Redux Middleware: async actions

Проблема: Reducers должны быть чистыми функциями. Как обрабатывать async операции (API запросы)?

Решение: Middleware (например, Redux Thunk)

import { createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk";

// Action creator с async (thunk)
const fetchUser = (userId) => async (dispatch) => {
  dispatch({ type: "SET_LOADING", payload: true });
  
  try {
    const response = await fetch(`/api/users/${userId}`);
    const user = await response.json();
    
    dispatch({
      type: "SET_USER",
      payload: user
    });
  } catch (error) {
    dispatch({
      type: "SET_ERROR",
      payload: error.message
    });
  } finally {
    dispatch({ type: "SET_LOADING", payload: false });
  }
};

// Применяем middleware
const store = createStore(appReducer, applyMiddleware(thunk));

// Теперь можем dispatch функции вместо объектов
dispatch(fetchUser(123));

Правила Redux Flow

1. Actions должны быть простыми объектами

// Правильно
{ type: "INCREMENT", payload: 5 }

// Неправильно
dispatch(() => { ... })

2. Reducers должны быть чистыми

// Правильно
return { ...state, count: state.count + 1 }

// Неправильно
state.count += 1;  // мутация!
return state;

3. Не мутируй state

// Неправильно
case "ADD_TODO":
  state.todos.push(action.payload);
  return state;

// Правильно
case "ADD_TODO":
  return {
    ...state,
    todos: [...state.todos, action.payload]
  };

Redux DevTools

const store = createStore(
  appReducer,
  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);

// Теперь можешь инспектировать state и actions в браузере

Redux vs Context API

ReduxContext API
Больше boilerplateМеньше code
DevToolsНет devtools
МасштабируемоХорошо для small apps
ПредсказуемоПростая
Требует обученияЛегче учить

Вывод

Redux Flow:

  1. User взаимодействует с UI
  2. UI dispatch(action) — отправляет action в store
  3. Reducer обрабатывает action и возвращает новое state
  4. Store обновляется
  5. Компоненты, подписанные через useSelector, перерендерятся

Это однонаправленный, предсказуемый поток, который делает state management прозрачным и легким для отладки.