第三节:Redux Toolkit 使用详解 和 RTK的异步操作
一. Redux Toolkit详解
1. 简介
(1).Redux Toolkit 是官方推荐的编写 Redux 逻辑的方法。
在前面我们学习Redux的时候应该已经发现,redux的编写逻辑过于的繁琐和麻烦。
并且代码通常分拆在多个文件中(虽然也可以放到一个文件管理,但是代码量过多,不利于管理);
Redux Toolkit包旨在成为编写Redux逻辑的标准方式,从而解决上面提到的问题;
在很多地方为了称呼方便,也将之称为“RTK”;
(2).需要安装下面两个包
【npm install @reduxjs/toolkit react-redux】
(3).Redux Toolkit的核心API主要是如下几个:
configureStore:包装createStore以提供简化的配置选项和良好的默认值。它可以自动组合你的 slice reducer,添加你提供的任何 Redux 中间件,redux-thunk默认包含,并启用 Redux DevTools Extension。
createSlice:接受reducer函数的对象、切片名称和初始状态值,并自动生成切片reducer,并带有相应的actions。
createAsyncThunk: 接受一个动作类型字符串和一个返回承诺的函数,并生成一个pending/fulfilled/rejected基于该承诺分派动作类型的 thunk
2. createSlice剖析
(1) createSlice主要包含如下几个参数:
◼ name:用户标记slice的名词: 在之后的redux-devtool中会显示对应的名词;
◼ initialState:初始化值,第一次初始化时的值;
◼ reducers:相当于之前的reducer函数
对象类型,并且可以添加很多的函数; 函数类似于redux原来reducer中的一个case语句; 函数的参数:
✓ 参数一:state
✓ 参数二:调用这个action时,传递的action参数;
(2) 返回值
◼ createSlice返回值是一个对象,包含所有的actions;
3. configureStore剖析
用于创建store对象,常见参数如下:
reducer,将slice中的reducer可以组成一个对象传入此处;
middleware:可以使用参数,传入其他的中间件(自行了解);
devTools:是否配置devTools工具,默认为true;
详见:store/index.js
4. 实操
(1). 安装相关的包 【npm install react-redux @reduxjs/toolkit 】
(2). 在count.js 和 home1.js 中通过createSlice配置初始化数据和reducer,然后对外导出action和reducer
import { createSlice } from '@reduxjs/toolkit';
const countSlice = createSlice({
name: 'myCount',
initialState: {
counter: 100,
},
// 这个的reducer相当于之前单独的reducer中switch的逻辑
reducers: {
addNumberAction(state, action) {
state.counter = state.counter + action.payload;
},
// payload是对action的解构
subNumberAction(state, { payload }) {
state.counter = state.counter - payload;
},
},
});
// 对外导出reducer的方法 和 reducer
// 解构的同时对外导出
export const { addNumberAction, subNumberAction } = countSlice.actions;
export default countSlice.reducer;
(3). 在store/index.js 中通过 configureStore 配置多个reducer,这里给子reducer命名,如: ypfCount,后续调用的时候要使用
import { configureStore } from '@reduxjs/toolkit';
import countReducer from './count';
import homeReducer from './home2';
const store = configureStore({
reducer: {
ypfCount: countReducer,
ypfHome: homeReducer,
},
// 是否配置devTools工具,默认为true;
devTools: true,
});
export default store;
(4). 在pages文件夹下的 zAbout组件、zCateGory2组件中进行store数据的使用
A. 导入各种reducer中的action
B. 通过 mapStateToProps 和 mapDispatchToProps 进行数据和方法映射
二. RTK异步操作
1. 写法1---写法简洁,个人喜欢
(1). 通过Redux Toolkit默认已经给我们继承了Thunk相关的功能:createAsyncThunk,在其内部发送请求,获取数据。
(2). 直接通过 dispatch(xxxAction) 修改store里的数据
详见: store/home1.js
需要把:zCategory2中的引用改为: ../store/home1
store/index.js中的引用改为:../store/home1
查看代码
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import axios from 'axios';
const homeSlice = createSlice({
name: 'myHome',
initialState: {
banners: [],
recommends: [],
},
reducers: {
changeBannersAction(state, action) {
state.banners = action.payload;
},
//这里的payload是对action的解构
changeRecommendsAction(state, { payload }) {
state.recommends = payload;
},
},
});
// 异步操作需要单独处理--createAsyncThunk
// 写法1: 直接使用dispatch修改store里的数据
export const fetchHomeMultidataAction = createAsyncThunk('GetHomeData', async (extraInfo, { dispatch, getState }) => {
// 1.发送网络请求, 获取数据
const res = await axios.get('http://xxx:8000/home/multidata');
// 2.取出数据, 并且在此处直接dispatch操作(可以不做)
const banners = res.data.data.banner.list;
const recommends = res.data.data.recommend.list;
// 下面两个dispathch可以直接修改赋值,就不用写下面的extraReducer了
dispatch(changeBannersAction(banners));
dispatch(changeRecommendsAction(recommends));
});
// 对外导出
// 解构的同时对外导出
export const { changeBannersAction, changeRecommendsAction } = homeSlice.actions;
export default homeSlice.reducer;
2. 写法2--官方推荐的
(1). 通过Redux Toolkit默认已经给我们继承了Thunk相关的功能:createAsyncThunk,在其内部发送请求,获取数据。
(2). 通过createSlice中的extraReducers进行监听状态,可以写成计算属性的模式 或 函数的模式,有三种状态
pending:action被发出,但是还没有最终的结果;
fulfilled:获取到最终的结果(有返回值的结果);
rejected:执行过程中有错误或者抛出了异常;
(3). 另外需要配合 createAsyncThunk 中返回数据
详见: store/home2.js
需要把:zCategory2中的引用改为: ../store/home2
store/index.js中的引用改为:../store/home2
查看代码
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import axios from 'axios';
// 异步操作需要单独处理--createAsyncThunk
// 写法2: 使用homeSlice中的extraReducers进行监听
export const fetchHomeMultidataAction = createAsyncThunk('GetHomeData', async (extraInfo, { dispatch, getState }) => {
// 1.发送网络请求, 获取数据
const res = await axios.get('http://xxx:8000/home/multidata');
// 2. 返回数据
return res.data;
});
const homeSlice = createSlice({
name: 'myHome',
initialState: {
banners: [],
recommends: [],
},
reducers: {
changeBannersAction(state, action) {
state.banners = action.payload;
},
//这里的payload是对action的解构
changeRecommendsAction(state, { payload }) {
state.recommends = payload;
},
},
// extraReducers--计算属性的写法
// 为了简便,可以只监听成功的状态fulfilled,解构出来的payLoad就是上述fetchHomeMultidataAction返回的数据res.data
/* extraReducers: {
[fetchHomeMultidataAction.pending](state, action) {
console.log('fetchHomeMultidataAction.pending');
},
// payLoad是对action的解构
[fetchHomeMultidataAction.fulfilled](state, { payload }) {
state.banners = payload.data.banner.list;
state.recommends = payload.data.recommend.list;
},
[fetchHomeMultidataAction.rejected](state, action) {
console.log('fetchHomeMultidataAction.pending');
},
}, */
// extraReducers--函数写法
extraReducers: (builder) => {
builder
.addCase(fetchHomeMultidataAction.pending, (state, action) => {
console.log('fetchHomeMultidataAction pending');
})
.addCase(fetchHomeMultidataAction.fulfilled, (state, { payload }) => {
state.banners = payload.data.banner.list;
state.recommends = payload.data.recommend.list;
});
},
});
// 对外导出
// 解构的同时对外导出
export const { changeBannersAction, changeRecommendsAction } = homeSlice.actions;
export default homeSlice.reducer;
!
- 作 者 : Yaopengfei(姚鹏飞)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 声 明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
- 声 明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。