@reduxjs/toolkit — это официальная, рекомендованная библиотека для эффективной работы с Redux. Она упрощает и оптимизирует разработку с использованием Redux, предоставляя множество удобных инструментов и абстракций для управления состоянием приложения.
Основные возможности @reduxjs/toolkit
- Упрощённая конфигурация хранилища (store).
- Автоматическое создание редьюсеров и экшенов.
- Интеграция с асинхронными операциями.
- Поддержка TypeScript из коробки.
- Инструменты для нормализации данных и кэширования запросов.
Установка
npm install @reduxjs/toolkit
Или с использованием Yarn:
yarn add @reduxjs/toolkit
Создание хранилища с configureStore
Функция configureStore
упрощает создание хранилища Redux с предустановленными редьюсерами и миддлварами.
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './counterSlice';
const store = configureStore({
reducer: {
counter: counterReducer
}
});
export default store;
Создание срезов (slices)
Срезы (slices) — это абстракция, объединяющая редьюсеры и экшены в одно целое. Они упрощают управление состоянием и написание редьюсеров.
import { createSlice } from '@reduxjs/toolkit';
const counterSlice = createSlice({
name: 'counter',
initialState: {
value: 0
},
reducers: {
increment: state => {
state.value += 1;
},
decrement: state => {
state.value -= 1;
},
incrementByAmount: (state, action) => {
state.value += action.payload;
}
}
});
export const { increment, decrement, incrementByAmount } = counterSlice.actions;
export default counterSlice.reducer;
Использование в компонентах React
С помощью useSelector
и useDispatch
вы можете легко интегрировать Redux с компонентами React.
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement, incrementByAmount } from './counterSlice';
const Counter = () => {
const count = useSelector(state => state.counter.value);
const dispatch = useDispatch();
return (
{count}
);
};
export default Counter;
Асинхронные операции с createAsyncThunk
Функция createAsyncThunk
упрощает создание асинхронных операций в Redux, таких как запросы к API.
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import axios from 'axios';
export const fetchUserById = createAsyncThunk(
'users/fetchByIdStatus',
async (userId, thunkAPI) => {
const response = await axios.get(`/api/user/${userId}`);
return response.data;
}
);
const userSlice = createSlice({
name: 'user',
initialState: {
entities: [],
loading: 'idle'
},
reducers: {},
extraReducers: builder => {
builder
.addCase(fetchUserById.pending, (state, action) => {
state.loading = 'loading';
})
.addCase(fetchUserById.fulfilled, (state, action) => {
state.entities.push(action.payload);
state.loading = 'idle';
})
.addCase(fetchUserById.rejected, (state, action) => {
state.loading = 'idle';
});
}
});
export default userSlice.reducer;
Создание и использование селекторов
Selectors (селекторы) — это функции, которые извлекают данные из состояния Redux. Они позволяют создавать переиспользуемые и оптимизированные запросы к состоянию.
import { createSelector } from '@reduxjs/toolkit';
const selectSelf = state => state.user;
export const selectUserById = createSelector(
[selectSelf, (state, userId) => userId],
(user, userId) => user.entities.find(user => user.id === userId)
);
// Использование в компоненте React
import React from 'react';
import { useSelector } from 'react-redux';
import { selectUserById } from './userSlice';
const UserComponent = ({ userId }) => {
const user = useSelector(state => selectUserById(state, userId));
return {user ? user.name : 'Загрузка...'};
};
export default UserComponent;
Нормализация данных с createEntityAdapter
Функция createEntityAdapter
упрощает управление коллекциями данных, обеспечивая автоматическую нормализацию и оптимизацию операций с данными.
import { createSlice, createEntityAdapter } from '@reduxjs/toolkit';
const usersAdapter = createEntityAdapter();
const initialState = usersAdapter.getInitialState({
loading: 'idle'
});
const usersSlice = createSlice({
name: 'users',
initialState,
reducers: {
addUser: usersAdapter.addOne,
addUsers: usersAdapter.addMany,
updateUser: usersAdapter.updateOne,
removeUser: usersAdapter.removeOne
}
});
export const { addUser, addUsers, updateUser, removeUser } = usersSlice.actions;
export default usersSlice.reducer;
// Использование в компоненте React
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { fetchUserById, addUser } from './usersSlice';
const UsersComponent = () => {
const dispatch = useDispatch();
const users = useSelector(state => state.users.entities);
const loading = useSelector(state => state.users.loading);
useEffect(() => {
dispatch(fetchUserById(1));
}, [dispatch]);
const handleAddUser = () => {
dispatch(addUser({ id: 2, name: 'John Doe' }));
};
return (
{loading === 'loading' ? 'Загрузка...' : users.map(user => {user.name})}
);
};
export default UsersComponent;
Заключение
@reduxjs/toolkit — это мощный инструмент для упрощения и оптимизации работы с Redux. Он предоставляет удобные и эффективные методы для создания и управления состоянием, обработки асинхронных операций и нормализации данных, делая разработку с использованием Redux более приятной и продуктивной.