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;