В чем разница между Redux и ReduxToolKit?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Redux vs Redux Toolkit: полное сравнение
Redux Toolkit (RTK) — это официально рекомендованный способ написания Redux логики. Он включает в себя инструменты для упрощения типичных Redux сценариев, снижения количества кода и предотвращения распространенных ошибок. Redux Toolkit на 100% совместим с обычным Redux, но значительно упрощает разработку.
История
Redux был создан Дэн Абрамовым в 2015 году и стал стандартом управления состоянием в React приложениях.
Redux Toolkit был создан командой Redux в 2019 году как официальное решение для упрощения Redux разработки.
Основные различия
1. Объем кода
Redux (traditional):
// action types
const INCREMENT = "INCREMENT";
const DECREMENT = "DECREMENT";
// action creators
const increment = () => ({ type: INCREMENT });
const decrement = () => ({ type: DECREMENT });
// reducer
const counterReducer = (state = 0, action) => {
switch (action.type) {
case INCREMENT:
return state + 1;
case DECREMENT:
return state - 1;
default:
return state;
}
};
// store
import { createStore } from "redux";
const store = createStore(counterReducer);
Redux Toolkit:
import { createSlice } from "@reduxjs/toolkit";
const counterSlice = createSlice({
name: "counter",
initialState: 0,
reducers: {
increment: (state) => state + 1,
decrement: (state) => state - 1,
},
});
export const { increment, decrement } = counterSlice.actions;
export default counterSlice.reducer;
Redux Toolkit требует в 2-3 раза меньше кода.
2. Неизменяемость (Immutability)
Redux требует ручной заботы об неизменяемости:
// Нужно осторожно обновлять объекты
const todoReducer = (state = [], action) => {
switch (action.type) {
case ADD_TODO:
// Неправильно: мутирует состояние
// state.push(action.payload);
// return state;
// Правильно: создает новый массив
return [...state, action.payload];
case UPDATE_TODO:
// Неправильно: мутирует объект
// state[0].title = "new title";
// Правильно: создает новые объекты
return state.map(todo =>
todo.id === action.payload.id
? { ...todo, ...action.payload }
: todo
);
default:
return state;
}
};
Redux Toolkit использует Immer.js для безопасной работы с состоянием:
const todoSlice = createSlice({
name: "todos",
initialState: [],
reducers: {
addTodo: (state, action) => {
// Можно писать как мутирующий код, Immer позаботится
state.push(action.payload);
},
updateTodo: (state, action) => {
const todo = state.find(t => t.id === action.payload.id);
if (todo) {
// Выглядит как мутация, но на самом деле безопасно
todo.title = action.payload.title;
}
},
},
});
3. DevTools интеграция
Redux:
import { createStore, applyMiddleware, compose } from "redux";
const composeEnhancers =
typeof window === "object" && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({})
: compose;
const store = createStore(
rootReducer,
composeEnhancers(applyMiddleware(...middleware))
);
Redux Toolkit:
import { configureStore } from "@reduxjs/toolkit";
const store = configureStore({
reducer: {
counter: counterReducer,
todos: todosReducer,
},
});
// Redux DevTools уже интегрированы!
4. Обработка асинхронных операций
Redux:
import { createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk";
// Action creator
const fetchUsers = () => {
return (dispatch) => {
dispatch({ type: "FETCH_START" });
fetch("/api/users")
.then(res => res.json())
.then(data => {
dispatch({ type: "FETCH_SUCCESS", payload: data });
})
.catch(error => {
dispatch({ type: "FETCH_ERROR", payload: error });
});
};
};
const store = createStore(rootReducer, applyMiddleware(thunk));
Redux Toolkit:
import { createAsyncThunk, createSlice, configureStore } from "@reduxjs/toolkit";
// Асинхронный thunk
const fetchUsers = createAsyncThunk(
"users/fetchUsers",
async (_, { rejectWithValue }) => {
try {
const response = await fetch("/api/users");
if (!response.ok) throw new Error("Failed to fetch");
return await response.json();
} catch (error) {
return rejectWithValue(error.message);
}
}
);
const usersSlice = createSlice({
name: "users",
initialState: { data: [], loading: false, error: null },
extraReducers: (builder) => {
builder
.addCase(fetchUsers.pending, (state) => {
state.loading = true;
})
.addCase(fetchUsers.fulfilled, (state, action) => {
state.loading = false;
state.data = action.payload;
})
.addCase(fetchUsers.rejected, (state, action) => {
state.loading = false;
state.error = action.payload;
});
},
});
const store = configureStore({
reducer: usersSlice.reducer,
});
5. Middleware
Redux:
// Кастомный middleware
const logger = store => next => action => {
console.log("Action:", action);
const result = next(action);
console.log("New state:", store.getState());
return result;
};
const store = createStore(
rootReducer,
applyMiddleware(logger, thunk)
);
Redux Toolkit:
import { configureStore } from "@reduxjs/toolkit";
const store = configureStore({
reducer: rootReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(logger),
});
// Включены: thunk, logger в разработке по умолчанию
6. Query (RTK Query)
Redux Toolkit Query — это встроенная библиотека для управления кэшем данных от сервера:
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
const api = createApi({
reducerPath: "api",
baseQuery: fetchBaseQuery({ baseUrl: "https://api.example.com" }),
endpoints: (builder) => ({
getUsers: builder.query({
query: () => "/users",
}),
updateUser: builder.mutation({
query: (id, data) => ({
url: `/users/${id}`,
method: "PUT",
body: data,
}),
}),
}),
});
export const { useGetUsersQuery, useUpdateUserMutation } = api;
Таблица сравнения
| Параметр | Redux | Redux Toolkit |
|---|---|---|
| Объем кода | Большой | Минимальный |
| Кривая обучения | Крутая | Пологая |
| DevTools | Ручная настройка | По умолчанию |
| Immer интеграция | Нет | Да |
| Async обработка | redux-thunk | createAsyncThunk |
| API запросы | Вручную | RTK Query |
| Производительность | Хорошо | Отлично |
| TypeScript поддержка | Хорошо | Отлично |
| Мидлвары | Нужно устанавливать | Включены по умолчанию |
| Рекомендация | Не рекомендуется для новых проектов | Официально рекомендуется |
Миграция с Redux на Redux Toolkit
// До: Redux
const INCREMENT = "INCREMENT";
const increment = () => ({ type: INCREMENT });
const reducer = (state = 0, action) => {
switch (action.type) {
case INCREMENT:
return state + 1;
default:
return state;
}
};
// После: Redux Toolkit
const slice = createSlice({
name: "counter",
initialState: 0,
reducers: {
increment: (state) => state + 1,
},
});
export const { increment } = slice.actions;
export default slice.reducer;
Вывод
Выбирайте Redux Toolkit, если:
- Начинаете новый проект
- Хотите писать меньше boilerplate кода
- Нужна встроенная поддержка DevTools
- Нужна работа с асинхронностью
- Нужен RTK Query для API запросов
Redux может быть полезен только, если:
- Работаете с очень старым codebases
- Нужна минимальная зависимость от библиотек
Официально Redux рекомендует использовать Redux Toolkit для всех новых разработок.