Redux Toolkit

概述

官方推出的 Redux 工具,对 Redux 进行的二次封装,用于高效 Redux 开发,使用简单。

yarn add @reduxjs/toolkit react-redux

创建状态切片

状态切片,可以认为它是 Redux 中一个个小的 Reducer 函数。

在 Redux 中,原本 Reducer 函数和 Action 对象需要分别创建,现在通过状态切片替代,它会返回 Reducer 函数和 Action 对象。

store/todos.js

import { createSlice } from '@reduxjs/toolkit'; export const TODOS_FEATURE_KEY = 'todos'; const { reducer: ToolsReducer, actions } = createSlice({ name: TODOS_FEATURE_KEY, initialState: [], reducers: { addTodo: (state, action) => { state.push(action.payload) } } }); export const { addTodo } = actions; export default ToolsReducer;

创建 Store

store/index.js

import { configureStore } from '@reduxjs/toolkit'; import TodosReducer, { TODOS_FEATURE_KEY } from './todos'; export default configureStore({ reducer: { [TODOS_FEATURE_KEY]: TodosReducer }, devTools: process.env.NODE_ENV !== 'production' });

Action 预处理

当 Action 被触发后,可以通过 prepare 方法对 Action 进行预处理,处理完成后交给 Reudcer.prepare 方法必须返回对象。

store/todos.js

import { createSlice } from '@reduxjs/toolkit'; export const TODOS_FEATURE_KEY = 'todos'; const { reducer: ToolsReducer, actions } = createSlice({ name: TODOS_FEATURE_KEY, initialState: [], reducers: { // addTodo: (state, action) => { // state.push(action.payload) // } addTodo: { reducer: (state, action) => { state.push(action.payload) }, prepare: todo => { return { payload: { id: Math.random(), ...todo } } } } } }); export const { addTodo } = actions; export default ToolsReducer;

异步操作

创建异步操作函数

import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'; export const TODOS_FEATURE_KEY = 'todos'; export const loadTodos = createAsyncThunk( 'todos/loadTodos', (payload, thunkAPI) => { axios.get(payload).then(response => thunkAPI.dispatch(setTodos(response.data))) } )

接收异步操作结果

const { reducer: ToolsReducer, actions } = createSlice({ name: TODOS_FEATURE_KEY, initialState: [], reducers: { // addTodo: (state, action) => { // state.push(action.payload) // } addTodo: { reducer: (state, action) => { state.push(action.payload) }, prepare: todo => { return { payload: { id: Math.random(), ...todo } } } }, setTodos: (state, action) => { action.payload.forEach(todo => state.push(todo)); } } }); export const { addTodo, setTodos } = actions; export default ToolsReducer;

实体适配器

将状态放入实体适配器,实体适配器提供操作状态的各种方法,简化操作。

import { createSlice, createAsyncThunk, createEntityAdapter } from '@reduxjs/toolkit'; const todosAdapter = createEntityAdapter(); export const TODOS_FEATURE_KEY = 'todos'; export const loadTodos = createAsyncThunk( 'todos/loadTodos', (payload, thunkAPI) => { axios.get(payload).then(response => thunkAPI.dispatch(setTodos(response.data))) } ) const { reducer: ToolsReducer, actions } = createSlice({ name: TODOS_FEATURE_KEY, initialState: todosAdapter.getInitialState(), reducers: { addTodo: { reducer: (state, action) => { todosAdapter.addOne(state, action.payload); }, prepare: todo => { return { payload: { id: Math.random(), ...todo } } } }, setTodos: (state, action) => { todosAdapter.addMany(state, action.payload); } }, extraReducers: {} }); export const { addTodo, setTodos } = actions; export default ToolsReducer;

简化实体适配器代码

todosAdapter 的方法会检测传入的参数,如果传入的是 action,会寻找 action.payload。

import { createSlice, createAsyncThunk, createEntityAdapter } from '@reduxjs/toolkit'; const todosAdapter = createEntityAdapter(); export const TODOS_FEATURE_KEY = 'todos'; export const loadTodos = createAsyncThunk( 'todos/loadTodos', (payload, thunkAPI) => { axios.get(payload).then(response => thunkAPI.dispatch(setTodos(response.data))) } ) const { reducer: ToolsReducer, actions } = createSlice({ name: TODOS_FEATURE_KEY, initialState: todosAdapter.getInitialState(), reducers: { addTodo: { reducer: todosAdapter.addOne, prepare: todo => { return { payload: { id: Math.random(), ...todo } } } }, setTodos: todosAdapter.addMany }, extraReducers: {} }); export const { addTodo, setTodos } = actions; export default ToolsReducer;

状态选择器

提供从实体适配器中获取状态的快捷途径。

import { createSelector } from '@reduxjs/toolkit'; const { selectAll } = todosAdapter.getSelectors(); export const selectTodosList = createSelector( state => state[TODOS_FEATURE_KEY], selectAll )
import { createSlice, createAsyncThunk, createEntityAdapter, createSelector } from '@reduxjs/toolkit'; const todosAdapter = createEntityAdapter(); export const TODOS_FEATURE_KEY = 'todos'; export const loadTodos = createAsyncThunk( 'todos/loadTodos', (payload, thunkAPI) => { axios.get(payload).then(response => thunkAPI.dispatch(setTodos(response.data))) } ) const { reducer: ToolsReducer, actions } = createSlice({ name: TODOS_FEATURE_KEY, initialState: todosAdapter.getInitialState(), reducers: { addTodo: { reducer: todosAdapter.addOne, prepare: todo => { return { payload: { id: Math.random(), ...todo } } } }, setTodos: todosAdapter.addMany }, extraReducers: {} }); const { selectAll } = todosAdapter.getSelectors(); export const selectTodos = createSelector(state => state[TODOS_FEATURE_KEY], selectAll); export const { addTodo, setTodos } = actions; export default ToolsReducer;