Назад
Назад к заметкам
· 4 мин чтения

Redux: управляемое состояние в React-приложениях

Redux собирает состояние React-приложения в единый store, упрощая отладку, тестирование и работу с асинхронными запросами.

reactstate-managementreduxperformance

Когда список товаров “лагает”, а кнопка “Добавить в корзину” не меняет количество, значит, состояние рассредоточено. Redux собирает его в одно место, делая данные предсказуемыми и удобными для тестов.


Что такое Redux и зачем он нужен?

Redux библиотека для управления состоянием в JavaScript-приложениях. Она предоставляет единый источник истины store, где хранится все UI-состояние. Вместо разбросанных useState по сотням компонентов вы держите данные в одном месте и меняете их через actions и reducers. Это упрощает отладку и позволяет откатывать изменения (time-travel debugging).


Ключевые понятия Redux

ЭлементОписание
StoreХранилище, в котором лежит все состояние приложения
ActionОбъект { type, payload }, описывающий событие
ReducerФункция (state, action) => newState принимает состояние и действие, возвращает новое
MiddlewareПлазма между dispatch и reducer. Позволяет работать с асинхронностью, логированием и т.п.

Эти четыре концепции образуют цикл данных: UI → dispatch(action) → middleware → reducer → новый state → UI.


Минимальный пример store в React

// store.js
import { createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk"; // middleware для async-логики

// Начальное состояние
const initialState = {
  cart: [],
};

// Reducer
function cartReducer(state = initialState, action) {
  switch (action.type) {
    case "ADD_ITEM":
      return { ...state, cart: [...state.cart, action.payload] };
    case "REMOVE_ITEM":
      return {
        ...state,
        cart: state.cart.filter((i) => i.id !== action.payload.id),
      };
    default:
      return state;
  }
}

export const store = createStore(cartReducer, applyMiddleware(thunk));
// component.jsx
import React from "react";
import { useSelector, useDispatch } from "react-redux";

export default function Cart() {
  const cart = useSelector((state) => state.cart);
  const dispatch = useDispatch();

  const addItem = (item) => dispatch({ type: "ADD_ITEM", payload: item });

  return (
    <div>
      <h2>Корзина</h2>
      <ul>
        {cart.map((i) => (
          <li key={i.id}>{i.name}</li>
        ))}
      </ul>
      <button onClick={() => addItem({ id: Date.now(), name: "Товар" })}>
        Добавить
      </button>
    </div>
  );
}

Мы создали store, подключили thunk-middleware и получили рабочую корзину. Чтобы снизить количество ререндеров, посмотрите на мемоизацию компонентов.


Как добавлять асинхронную логику в Redux

Самая частая ошибка новичков выполнять запрос внутри reducer. Это нарушает чистоту функций и приводит к непредсказуемым багам. Перенесите запрос в middleware. Самый популярный вариант redux-thunk, который позволяет писать асинхронные action-creators:

// actions.js
export const fetchProducts = () => async (dispatch) => {
  dispatch({ type: "PRODUCTS_PENDING" });
  try {
    const res = await fetch("/api/products");
    const data = await res.json();
    dispatch({ type: "PRODUCTS_FULFILLED", payload: data });
  } catch (e) {
    dispatch({ type: "PRODUCTS_REJECTED", error: e });
  }
};

Такой подход делает состояние предсказуемым и упрощает тестирование. Для более строгого контроля побочных эффектов обратите внимание на Redux-Saga.


Когда (и когда не) использовать Redux

СценарийРекомендация
Простой UI-компонент с несколькими локальными стейтамиДостаточно useState/useReducer
Большое приложение с множеством взаимосвязанных данныхRedux ваш главный помощник
Требуется сервер-сайд рендеринг (SSR)Подключайте configureStore из @reduxjs/toolkit
Нужно глобальное кэширование запросовСочетайте Redux с виртуализацией списка и React.memo

Если вы решили использовать Redux, начните с @reduxjs/toolkit. Он генерирует типовые action-creators и сокращает бойлерплейт, позволяя сосредоточиться на бизнес-логике.


FAQ / Чеклист

  • Не мутируйте state в reducer. Используйте спред-операторы или immer.
  • Не храните функции в Redux-state они не сериализуются и ломают DevTools.
  • Подключайте только нужные slice-ы через useSelector. Иначе каждый ререндер будет проверять все состояние.
  • Проверяйте типы action-ов (TypeScript или prop-types). Это защищает от опечаток.
  • Удаляйте подписки в кастомных хуках, если используете store.subscribe вручную.

Redux становится естественным выбором, когда приложение растет, а данные начинают пересекаться. Одна централизованная точка управления упрощает отладку, а DevTools позволяют восстановить любое состояние.

Готов начать?

Выбери удобный способ связи — напиши напрямую или оставь заявку

Написать в Telegram

Отвечу в течение пары часов