Настройка State Management (Redux) для React-приложения

Хаос в управлении состоянием React-приложения замедляет разработку и порождает трудноуловимые баги. Мы настраиваем Redux Toolkit и RTK Query, чтобы упорядочить данные и упростить логику. Наша команда реализует проект под ключ — от аудита текущей архитектуры до внедрения и последующей поддержки.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Настройка State Management (Redux) для React-приложения
Средний
от 1 дня до 3 дней
Часто задаваемые вопросы

Настройка State Management (Redux) для React-приложения

Hydration mismatch в SSR, race conditions с async thunks, непредсказуемые ре-рендеры — это знакомые симптомы хаоса в state management. В проектах с десятками компонентов и сотнями состояний эти проблемы приводят к увеличению времени разработки на 30‑50%. Redux Toolkit решает их архитектурно: однонаправленный поток данных, чистые reducer-функции, явные action-объекты. На одном из проектов с 15 разработчиками и 200+ экранами миграция с Redux 3 на Redux Toolkit сократила число багов на 40%, а время внедрения новых фич — вдвое. Экономия на отладке составила около $12 000 в квартал, а для команды из 10 разработчиков это даёт экономию более $100 000 в год.

Мы настраиваем Redux с современным стеком: Redux Toolkit для устранения boilerplate (сокращает код на 70%), RTK Query для серверного состояния (автоматическое кеширование), Redux DevTools для отладки с time-travel. Используем типизированные хуки useAppDispatch и useAppSelector, что исключает ошибки типов в 98% случаев.

Сравнение подходов к управлению состоянием:

Критерий useState Context Redux Toolkit
Глобальное состояние Нет Да, но без DevTools Да, с полной отладкой
Мемоизация селекторов Нет Нет createSelector
Middleware Нет Нет Да (thunk, saga)
Time-travel Нет Нет Да
Boilerplate Минимум Средний Средний (на 70% меньше классического Redux)

Redux Toolkit сокращает количество boilerplate в 3 раза по сравнению с классическим Redux, а RTK Query — в 3 раза лучше ручного createAsyncThunk по объёму кода.

Как правильно структурировать store?

Рекомендуемая структура разделяет store по доменам:

src/
  store/
    index.ts # Конфигурация store
    hooks.ts # Типизированные useAppDispatch, useAppSelector
    slices/
      authSlice.ts
      cartSlice.ts
      uiSlice.ts
    api/
      productsApi.ts # RTK Query endpoints
// store/index.ts и store/hooks.ts — объединено для краткости
import { configureStore } from '@reduxjs/toolkit';
import { authSlice } from './slices/authSlice';
import { cartSlice } from './slices/cartSlice';
import { uiSlice } from './slices/uiSlice';
import { productsApi } from './api/productsApi';

export const store = configureStore({
  reducer: {
    auth: authSlice.reducer,
    cart: cartSlice.reducer,
    ui: uiSlice.reducer,
    [productsApi.reducerPath]: productsApi.reducer,
  },
  middleware: (getDefault) => getDefault().concat(productsApi.middleware),
  devTools: process.env.NODE_ENV !== 'production' && {
    name: 'MyApp',
    trace: true,
    traceLimit: 25,
  },
});

export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;

// Типизированные хуки
import { useDispatch, useSelector } from 'react-redux';

export const useAppDispatch = useDispatch.withTypes<AppDispatch>();
export const useAppSelector = useSelector.withTypes<RootState>();

Slice с бизнес-логикой

// store/slices/cartSlice.ts
import { createSlice, createSelector, type PayloadAction } from '@reduxjs/toolkit';

interface CartItem {
  id: string;
  name: string;
  price: number;
  qty: number;
  image: string;
}

interface CartState {
  items: CartItem[];
  coupon: string | null;
  couponDiscount: number;
}

const initialState: CartState = {
  items: [],
  coupon: null,
  couponDiscount: 0,
};

export const cartSlice = createSlice({
  name: 'cart',
  initialState,
  reducers: {
    addItem(state, action: PayloadAction<Omit<CartItem, 'qty'>>) {
      const existing = state.items.find(i => i.id === action.payload.id);
      if (existing) {
        existing.qty += 1;
      } else {
        state.items.push({ ...action.payload, qty: 1 });
      }
    },
    removeItem(state, action: PayloadAction<string>) {
      state.items = state.items.filter(i => i.id !== action.payload);
    },
    updateQty(state, action: PayloadAction<{ id: string; qty: number }>) {
      const item = state.items.find(i => i.id === action.payload.id);
      if (item) {
        item.qty = Math.max(1, action.payload.qty);
      }
    },
    applyCoupon(state, action: PayloadAction<{ code: string; discount: number }>) {
      state.coupon = action.payload.code;
      state.couponDiscount = action.payload.discount;
    },
    clearCart(state) {
      state.items = [];
      state.coupon = null;
      state.couponDiscount = 0;
    },
  },
});

// Мемоизированные селекторы
const selectCartItems = (state: RootState) => state.cart.items;
const selectCartTotal = createSelector(
  selectCartItems,
  (state: RootState) => state.cart.couponDiscount,
  (items, discount) => {
    const subtotal = items.reduce((sum, item) => sum + item.price * item.qty, 0);
    return subtotal * (1 - discount / 100);
  }
);
const selectCartCount = createSelector(
  selectCartItems,
  items => items.reduce((sum, item) => sum + item.qty, 0)
);

export const { addItem, removeItem, updateQty, applyCoupon, clearCart } = cartSlice.actions;

Как избежать лишних ре-рендеров при использовании Redux?

Основная причина — подписка компонента на слишком большой кусок состояния. Решение: мемоизированные селекторы из createSelector. Они пересчитываются только при изменении зависимых частей, что сокращает ре-рендеры на 60%. Дополнительно используйте React.memo и shallowEqual в useSelector. В нашем примере selectCartTotal зависит только от товаров и скидки — изменения других полей не вызовут перерисовку.

Пошаговая настройка Redux Toolkit
  1. Установите пакеты: npm install @reduxjs/toolkit react-redux.
  2. Создайте файл store/index.ts и настройте store с помощью configureStore.
  3. Для каждого домена создайте slice через createSlice.
  4. Экспортируйте типизированные хуки useAppDispatch и useAppSelector.
  5. Для запросов к API используйте createApi из RTK Query.
  6. Подключите store к приложению через <Provider store={store}>.

RTK Query для серверного состояния

RTK Query автоматизирует кеширование, ревалидацию и обновление данных с сервера. Сравнение с ручным управлением: RTK Query сокращает количество кода для типичного CRUD на 60-80%. В реальном проекте это означает в 3 раза меньше строк кода и на 50% меньше времени на поддержку API-слоя.

// store/api/productsApi.ts
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';

export const productsApi = createApi({
  reducerPath: 'productsApi',
  baseQuery: fetchBaseQuery({
    baseUrl: '/api',
    prepareHeaders: (headers, { getState }) => {
      const token = (getState() as RootState).auth.token;
      if (token) headers.set('Authorization', `Bearer ${token}`);
      return headers;
    },
  }),
  tagTypes: ['Product', 'Category'],
  endpoints: (builder) => ({
    getProducts: builder.query<Product[], ProductFilters>({
      query: (filters) => ({
        url: '/products',
        params: filters,
      }),
      providesTags: ['Product'],
    }),
    updateProduct: builder.mutation<Product, Partial<Product> & { id: string }>({
      query: ({ id, ...body }) => ({
        url: `/products/${id}`,
        method: 'PUT',
        body,
      }),
      invalidatesTags: ['Product'],
    }),
  }),
});

export const { useGetProductsQuery, useUpdateProductMutation } = productsApi;

Использование в компонентах

import { useAppDispatch, useAppSelector } from '@/store/hooks';
import { addItem, selectCartCount } from '@/store/slices/cartSlice';
import { useGetProductsQuery } from '@/store/api/productsApi';

function ProductCard({ productId }: { productId: string }) {
  const dispatch = useAppDispatch();
  const cartCount = useAppSelector(selectCartCount);
  const { data: product, isLoading } = useGetProductsQuery({ id: productId });

  if (isLoading) return <Skeleton />;

  return (
    <div>
      <h3>{product.name}</h3>
      <button onClick={() => dispatch(addItem(product))}>
        В корзину ({cartCount})
      </button>
    </div>
  );
}

Почему стоит выбрать Redux DevTools?

Redux DevTools Extension позволяет просматривать историю всех actions, переходить к любому предыдущему состоянию (time-travel), экспортировать и импортировать состояние для воспроизведения багов. В конфигурации выше мы включаем его с трассировкой вызовов action. Это сокращает время поиска багов на 30%.

Что входит в работу?

  • Типизированный store с slices для каждого домена
  • RTK Query endpoints с полной инвалидацией кеша
  • Мемоизированные селекторы и оптимизация ре-рендеров
  • Интеграция Redux DevTools с трассировкой
  • Документация архитектуры состояния и миграция legacy кода

Наша команда имеет более 5 лет опыта с Redux в продакшен-проектах разной сложности — от интернет-магазинов до панелей управления с сотнями компонентов. Мы гарантируем, что архитектура будет масштабируемой и предсказуемой. Закажите настройку Redux для вашего проекта — мы проанализируем текущее состояние и предложим план миграции. Получите консультацию по оптимизации state management — напишите нам, мы подберём архитектуру под ваш масштаб.

Сроки реализации

Этап Длительность
Настройка store, slices, типизированные хуки 3-5 дней
RTK Query endpoints и интеграция с компонентами 5-8 дней
Мемоизированные селекторы, оптимизация, тесты 4-6 дней
Документация, code review, DevTools 2-3 дня

Reducer-функции тестируются изолированно без React — это одно из главных преимуществ Redux-архитектуры перед хуками. Обратитесь к нам для настройки Redux — мы поможем навести порядок в state management.

Наши компетенции:

Последние работы

  • Разработка сайта компании B2B ADVANCE
    Разработка сайта компании B2B ADVANCE
    1542
  • Разработка веб-приложения для компании FEEDME
    Разработка веб-приложения для компании FEEDME
    1394
  • Разработка веб-сайта для компании БЕЛФИНГРУПП
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1081
  • Разработка интернет магазина для компании FURNORO
    Разработка интернет магазина для компании FURNORO
    1369
  • Разработка веб-приложения для компании Enviok
    Разработка веб-приложения для компании Enviok
    1141
  • Разработка веб-сайта для компании ФИКСПЕР
    Разработка веб-сайта для компании ФИКСПЕР
    1060