Если вы устали от шаблонного кода, сложной настройки и многословности классического Redux, то Redux Toolkit (RTK) — это ваш спасательный круг. Официальный, рекомендованный подход для написания логики Redux, который радикально упрощает разработку, делая её быстрой, предсказуемой и приятной. Давайте разберёмся, как начать использовать этот мощный инструмент уже сегодня.
Что такое Redux Toolkit и зачем он нужен?
Redux Toolkit — это не замена Redux, а его официальный набор инструментов и лучших практик, «стандартный» способ написания Redux-логики. Он был создан для решения трёх ключевых проблем «ванильного» Redux:
- Слишком много шаблонного кода: создание action types, action creators, редюсеров вручную.
- Сложность настройки store: подключение middleware (например, для асинхронных операций с redux-thunk) вручную.
- Легко допустить ошибку: например, изменить состояние напрямую, нарушив принцип иммутабельности.
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, которая превращает его из инструмента с высокой пороговой стоимостью входа в удобный и современный фреймворк для управления состоянием. Начните с него, и вы вряд ли захотите возвращаться к старому подходу.