Redux Toolkit — управление состоянием в React

Redux Toolkit — современный рекомендуемый способ писать Redux. Он убирает большую часть шаблонного кода: store создаётся через configureStore, логика состояния описывается в createSlice, а React подключается через Provider.

Когда нужен Redux Toolkit

Redux Toolkit полезен, когда одно состояние нужно многим частям приложения: пользователь, корзина, сложные фильтры, права доступа, настройки интерфейса. Для одного счётчика или маленькой формы хватит useState.

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

Базовая настройка Redux Toolkit

Redux Toolkit стоит разбирать через полный минимальный цикл: slice, store, Provider и использование состояния в компоненте. Если один из этих шагов пропустить, Redux начинает казаться сложнее, чем он есть.

Раздел лучше проходить руками, а не просто копировать. Redux становится понятным, когда вы видите путь данных: action попадает в reducer, store обновляется, а компонент получает новое значение через selector.

Установка

npm install @reduxjs/toolkit react-redux

Создать slice

import { createSlice } from '@reduxjs/toolkit';

const initialState = {
  value: 0,
};

const counterSlice = createSlice({
  name: 'counter',
  initialState,
  reducers: {
    increment: (state) => {
      state.value += 1;
    },
    decrement: (state) => {
      state.value -= 1;
    },
    addAmount: (state, action) => {
      state.value += action.payload;
    },
  },
});

export const { increment, decrement, addAmount } = counterSlice.actions;
export default counterSlice.reducer;

Создать store

import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './features/counter/counterSlice';

export const store = configureStore({
  reducer: {
    counter: counterReducer,
  },
});

Подключить Provider

import React from 'react';
import ReactDOM from 'react-dom/client';
import { Provider } from 'react-redux';
import { store } from './store';
import App from './App';

ReactDOM.createRoot(document.getElementById('root')).render(
  <Provider store={store}>
    <App />
  </Provider>
);

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

import { useDispatch, useSelector } from 'react-redux';
import { increment, decrement } from './features/counter/counterSlice';

function Counter() {
  const value = useSelector(state => state.counter.value);
  const dispatch = useDispatch();

  return (
    <div>
      <button onClick={() => dispatch(decrement())}>-</button>
      <span>{value}</span>
      <button onClick={() => dispatch(increment())}>+</button>
    </div>
  );
}

Почему внутри reducer будто можно мутировать state

Redux Toolkit использует Immer. Вы пишете state.value += 1, но под капотом создаётся корректная неизменяемая копия состояния. Это делает код короче и снижает риск ошибок.

Важно не переносить это правило за пределы Redux Toolkit. В обычном React state по-прежнему нельзя мутировать напрямую. Immer работает внутри createSlice и делает удобный синтаксис безопасным именно в этом контексте.

Мини-проект: todoSlice

import { createSlice } from '@reduxjs/toolkit';

const todoSlice = createSlice({
  name: 'todos',
  initialState: [],
  reducers: {
    addTodo: {
      reducer: (state, action) => {
        state.unshift(action.payload);
      },
      prepare: (text) => ({
        payload: { id: Date.now(), text, done: false },
      }),
    },
    toggleTodo: (state, action) => {
      const todo = state.find(item => item.id === action.payload);
      if (todo) todo.done = !todo.done;
    },
  },
});

export const { addTodo, toggleTodo } = todoSlice.actions;
export default todoSlice.reducer;

prepare создаёт payload до попадания в reducer. Это удобно, если нужно добавить id, дату или привести данные к единому формату.

Как не злоупотреблять Redux

  • Не кладите в Redux состояние одного input.
  • Не копируйте туда данные, которые уже хранит TanStack Query.
  • Не создавайте один огромный slice на весь проект.
  • Не пишите асинхронный код прямо в reducer.

После первого slice

После createSlice изучите createAsyncThunk или RTK Query. Но сначала важно уверенно понимать store, reducer, action, dispatch и selector.

Хорошее упражнение — добавить асинхронную загрузку списка и сравнить createAsyncThunk с TanStack Query. Так быстрее становится понятно, какие данные относятся к клиентскому состоянию, а какие лучше оставить серверному кэшу.

Как понять, что Redux Toolkit не лишний

Redux Toolkit нужен не потому, что приложение на React, а когда состояние стало общим и сложным. Если данные нужны одному компоненту или ближайшему родителю, useState обычно проще и честнее.

Спросите себя, станет ли приложение проще после store. Если вы добавляете Redux только потому, что «так принято», код усложнится. Если он убирает props drilling и централизует действительно общую логику, решение оправдано.

Хорошие кандидаты для Redux

  • пользователь и права доступа;
  • корзина интернет-магазина;
  • сложные фильтры, которые нужны разным страницам;
  • настройки интерфейса;
  • состояние конструктора или редактора.

Что не стоит класть в Redux

Не отправляйте туда каждое поле формы, открытие маленького dropdown и данные API, которые уже нормально живут в TanStack Query. Чем меньше случайного состояния в store, тем проще поддерживать проект.

Практическая граница

Если вы тянете props через 4-5 уровней только ради одного действия или значения, пора подумать о глобальном состоянии. Если компонент рядом с данными, Redux, скорее всего, преждевременен.

Оцените статью
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x