Redux Toolkit: Быстрый старт без боли. Полное руководство для React-разработчиков

Redux Toolkit: Быстрый старт без боли. Полное руководство для React-разработчиков

Если вы устали от шаблонного кода, сложной настройки и многословности классического Redux, то Redux Toolkit (RTK) — это ваш спасательный круг. Официальный, рекомендованный подход для написания логики Redux, который радикально упрощает разработку, делая её быстрой, предсказуемой и приятной. Давайте разберёмся, как начать использовать этот мощный инструмент уже сегодня.

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

Redux Toolkit — это не замена Redux, а его официальный набор инструментов и лучших практик, «стандартный» способ написания Redux-логики. Он был создан для решения трёх ключевых проблем «ванильного» Redux:

  1. Слишком много шаблонного кода: создание action types, action creators, редюсеров вручную.
  2. Сложность настройки store: подключение middleware (например, для асинхронных операций с redux-thunk) вручную.
  3. Легко допустить ошибку: например, изменить состояние напрямую, нарушив принцип иммутабельности.

RTK инкапсулирует лучшие практики, предоставляя простые API для решения этих задач.

Важно: Redux Toolkit поставляется с redux-thunk «из коробки» и включает утилиту Immer, которая позволяет писать «мутирующую» логику обновления состояния, которая на самом деле создаёт корректные иммутабельные обновления.

Быстрый старт: Установка и базовая настройка

Начнём с самого простого. Установите пакеты в ваш React-проект:

1. Установка

npm install @reduxjs/toolkit react-redux

2. Создание «среза» (Slice) — сердце RTK

Ключевая концепция — Slice. Это функция, которая автоматически генерирует action creators и action types на основе переданных редюсеров. Она объединяет логику в одном месте.

// features/counter/counterSlice.js
import { createSlice } from '@reduxjs/toolkit';

const initialState = {
  value: 0,
};

export const counterSlice = createSlice({
  name: 'counter', // Уникальное имя для среза
  initialState,
  reducers: {
    // Здесь пишем редюсеры как функции, которые «мутируют» состояние (благодаря Immer)
    increment: (state) => {
      state.value += 1;
    },
    decrement: (state) => {
      state.value -= 1;
    },
    incrementByAmount: (state, action) => {
      state.value += action.payload;
    },
  },
});

// Экспортируем сгенерированные action creators
// Для редюсера 'increment' создаётся action creator с именем 'increment'
export const { increment, decrement, incrementByAmount } = counterSlice.actions;

// Экспортируем сам редюсер для добавления в store
export default counterSlice.reducer;

Совет: Обратите внимание, как просто добавляется логика. Не нужно вручную объявлять константы типов действий или писать громоздкие switch-конструкции.

3. Настройка Store

Создать store с помощью RTK — дело одной строки. Функция configureStore автоматически подключает redux-thunk, включает Redux DevTools Extension и добавляет middleware для проверки распространённых ошибок.

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

export const store = configureStore({
  reducer: {
    counter: counterReducer,
    // Здесь можно добавить другие редюсеры
  },
});

4. Подключение Store к React-приложению

Оберните ваше приложение в Provider из react-redux, передав созданный store.

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

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  
    
  
);

5. Использование в компонентах: хуки useSelector и useDispatch

В функциональных компонентах используйте хуки для доступа к состоянию и отправки действий.

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

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

  return (
    
{count}
); }

Асинхронная логика с createAsyncThunk

Для работы с API и асинхронными операциями RTK предоставляет функцию createAsyncThunk. Она генерирует thunk action creator, который диспатчит действия pending/fulfilled/rejected на основе Promise.

// features/posts/postsSlice.js
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import { fetchPostsApi } from './api'; // Ваша функция для запроса

export const fetchPosts = createAsyncThunk('posts/fetchPosts', async () => {
  const response = await fetchPostsApi();
  return response.data; // Возвращаемое значение становится `action.payload`
});

const postsSlice = createSlice({
  name: 'posts',
  initialState: { items: [], status: 'idle', error: null },
  extraReducers: (builder) => {
    builder
      .addCase(fetchPosts.pending, (state) => {
        state.status = 'loading';
      })
      .addCase(fetchPosts.fulfilled, (state, action) => {
        state.status = 'succeeded';
        state.items = action.payload;
      })
      .addCase(fetchPosts.rejected, (state, action) => {
        state.status = 'failed';
        state.error = action.error.message;
      });
  },
});

// Использование в компоненте:
// dispatch(fetchPosts());

FAQ: Часто задаваемые вопросы

Нужно ли знать классический Redux перед изучением Redux Toolkit?

Нет, это не обязательно. Redux Toolkit — это рекомендуемый способ изучения Redux сегодня. Он абстрагирует сложности и позволяет сразу писать чистый, эффективный код. Понимание основных концепций (store, actions, reducers) будет полезно, но глубокое знание старого API не требуется.

Можно ли мигрировать существующий проект с классического Redux на RTK?

Да, и это поощряется. Миграцию можно проводить постепенно, среза за срезом (slice by slice). Вы можете использовать RTK для новых функций, параллельно со старым кодом. Функции configureStore и createSlice отлично работают с уже существующими редюсерами.

Чем RTK Query отличается от createAsyncThunk?

RTK Query — это отдельный, более мощный инструмент внутри RTK для управления кэшированием данных, полученных с сервера. Он автоматически генерирует хуки для запросов и мутаций, управляет кэшем, загрузкой и ошибками. createAsyncThunk — это более низкоуровневая утилита для создания асинхронных действий, когда вам нужен полный контроль над жизненным циклом запроса и структурой состояния.

Обязательно ли использовать Immer и «мутирующий» синтаксис?

Нет, но это крайне рекомендуется. Вы можете по-прежнему возвращать новое состояние иммутабельно (например, return { ...state, value: state.value + 1 }), но использование Immer делает код намного чище и читабельнее, сводя к минимуму ошибки.

Redux Toolkit — это эволюция экосистемы Redux, которая превращает его из инструмента с высокой пороговой стоимостью входа в удобный и современный фреймворк для управления состоянием. Начните с него, и вы вряд ли захотите возвращаться к старому подходу.