文章目录
前言
都什么年代了还在抽。。。哦说错了,都什么年代了还在用React-Redux
?
快来看看Redux Toolkit
这个包,再也不用繁琐的创建Type常量,不用自己下载Thunk、middleware、immer等等插件全部集成到了Redux Toolkit
,使用起来和VueX
/ Pinia
一样方便!!!
认识Redux Toolkit
◼ Redux Toolkit 是官方推荐的编写 Redux 逻辑的方法。
在我们学习Redux的时候应该已经发现,redux的编写逻辑过于的繁琐和麻烦。
并且代码通常分拆在多个文件中(虽然也可以放到一个文件管理,但是代码量过多,不利于管理);
Redux Toolkit
包旨在成为编写Redux逻辑的标准方式,从而解决上面提到的问题;
在很多地方为了称呼方便,也将之称为“RTK”;
◼ 安装Redux Toolkit:
npm install @reduxjs/toolkit react-redux
◼ Redux Toolkit的核心API主要是如下几个:
configureStore:包装createStore以提供简化的配置选项和良好的默认值。它可以自动组合你的 slice reducer,添加你提供的任何 Redux 中间件,redux-thunk默认包含,并启用 Redux DevTools Extension。
createSlice:接受reducer函数的对象、切片名称和初始状态值,并自动生成切片reducer,并带有相应的actions。
createAsyncThunk: 接受一个动作类型字符串和一个返回承诺的函数,并生成一个pending/fulfilled/rejected基于该承诺分派动作类型的 thunk
Redux Toolkit使用方法
1、创建reducer
◼通过createSlice创建一个slice(切片)。
◼ createSlice主要包含如下几个参数:
◼ name:用户标记slice的名词
在之后的redux-devtool中会显示对应的名词;
◼ initialState:初始化值
第一次初始化时的值;
◼ reducers:相当于之前的reducer函数
对象类型,并且可以添加很多的函数;
函数类似于redux原来reducer中的一个case语句;
函数的参数:
✓ 参数一:state
✓ 参数二:调用这个action时,传递的action参数;
◼ createSlice返回值是一个对象,包含所有的actions;
如果对redux了解不清晰可以看我上一篇文章!
【React】Redux的使用详解 https://blog.csdn.net/m0_68324632/article/details/128819264
案例
-src
—store
------- features
------------- counter.js
import { createSlice } from '@reduxjs/toolkit'
const counterSlice = createSlice({
name: "counter",
initialState: {
counter: 666
},
reducers: {
addNumber(state, { payload }) {
state.counter += payload
},
subNumber(state, { payload }) {
state.counter -= payload
}
}
})
export const { addNumber, subNumber } = counterSlice.actions
export default counterSlice.reducer
2、创建store
◼ configureStore用于创建store对象,常见参数如下:
reducer,将slice中的reducer可以组成一个对象传入此处;
middleware:可以使用参数,传入其他的中间件;
devTools:是否配置devTools工具,默认为true;
案例
-src
—store
-------index.js
import { configureStore } from '@reduxjs/toolkit'
import counterReducer from './features/counter'
const store = configureStore({
reducer: {
counter: counterReducer,
}
})
export default store
3、在组件中使用
◼ connect高阶组件把redux映射到组件的props里
-src
—pages
-------Home.jsx
import React, { PureComponent } from "react";
import { connect } from "react-redux";
import { addNumber } from "../store/features/counter";
export class Home extends PureComponent {
addNumber(num) {
this.props.addNumber(num)
}
render() {
const { counter } = this.props;
return (
<div>
<h2>Home Counter: {counter}</h2>
<div>
<button onClick={e => this.addNumber(5)}>+5</button>
<button onClick={e => this.addNumber(8)}>+8</button>
</div>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
counter: state.counter.counter,
};
};
const mapDispatchToProps = (dispatch) => {
return{
addNumber(num) {
dispatch(addNumber(num))
},
}
}
export default connect(mapStateToProps,mapDispatchToProps)(Home);
Redux Toolkit的异步操作
◼ Redux Toolkit默认已经给我们继承了Thunk相关的功能:createAsyncThunk
export const fetchHomeMultidataAction = createAsyncThunk("fetch/homemultidata", async () => {
const res = await axios.get("http://123.207.32.32:8000/home/multidata")
return res.data
})
◼ 当createAsyncThunk创建出来的action被dispatch时,会存在三种状态:
pending:action被发出,但是还没有最终的结果;
fulfilled:获取到最终的结果(有返回值的结果);
rejected:执行过程中有错误或者抛出了异常;
◼ 我们可以在createSlice的entraReducer中监听这些结果:
extraReducers:{
[fetchHomeMultidataAction.pending](state,action) {
console.log("pending");
},
[fetchHomeMultidataAction.fulfilled](state,{payload}) {
state.banners =payload.data.banner.list
state.recommends =payload.data.recommend.list
console.log("fulfilled");
},
[fetchHomeMultidataAction.rejected](state,action) {
console.log("rejected");
}
}
extraReducer的另外一种写法
◼ extraReducer还可以传入一个函数,函数接受一个builder参数。
我们可以向builder中添加case来监听异步操作的结果:
链式调用
案例
-src
—store
------- features
------------- home.js
createAsyncThunk中完成异步操作
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import axios from "axios"
export const fetchHomeMultidataAction = createAsyncThunk("fetch/homemultidata", async () => {
const res = await axios.get("http://123.207.32.32:8000/home/multidata")
return res.data
})
const homeSlice = createSlice({
name: "home",
initialState: {
banners: [],
recommends: []
},
reducers: {
changeBanners(state, { payload }) {
state.banners = payload
},
changeRecommends(state, { payload }) {
state.recommends = payload
}
},
extraReducers:{
[fetchHomeMultidataAction.pending](state,action) {
console.log("pending");
},
[fetchHomeMultidataAction.fulfilled](state,{payload}) {
state.banners =payload.data.banner.list
state.recommends =payload.data.recommend.list
console.log("fulfilled");
},
[fetchHomeMultidataAction.rejected](state,action) {
console.log("rejected");
}
}
})
export const { changeBanners, changeRecommends } = homeSlice.actions
export default homeSlice.reducer
-src
—store
-------index.js
把home中的reducer挂载到store中
import { configureStore } from '@reduxjs/toolkit'
import counterReducer from './features/counter'
// 不同的reducer管理
import homeReducer from './features/home'
const store = configureStore({
reducer: {
counter: counterReducer,
home:homeReducer
}
})
export default store
-src
—pages
-------Home.jsx
在页面中使用
import React, { PureComponent } from "react";
import { connect } from "react-redux";
import { addNumber } from "../store/features/counter";
import { fetchHomeMultidataAction } from "../store/features/home";
export class Home extends PureComponent {
async componentDidMount() {
//dom渲染完成挂载阶段才能进行异步操作
this.props.fetchHomeMultidata();
}
addNumber(num) {
this.props.addNumber(num);
}
render() {
//取出从从rudex里传入props中管理的状态
const { counter, banners, recommends } = this.props;
return (
<div>
<h2>Home Counter: {counter}</h2>
<div>
<button onClick={(e) => this.addNumber(5)}>+5</button>
<button onClick={(e) => this.addNumber(8)}>+8</button>
</div>
<div className="banner">
<h2>轮播图</h2>
<ul>
{banners.map((item) => {
return <li key={item.title}> {item.title} </li>;
})}
</ul>
</div>
<div className="recommend">
<h2>推荐数据展示</h2>
<ul>
{recommends.map((item) => {
return <li key={item.title}> {item.title} </li>;
})}
</ul>
</div>
</div>
);
}
}
//把redux的state映射到Props
const mapStateToProps = (state) => {
return {
//counter的状态
counter: state.counter.counter,
//home的状态
banners: state.home.banners,
recommends: state.home.recommends,
};
};
//把Dispatch映射到Props
const mapDispatchToProps = (dispatch) => {
return {
addNumber(num) {
dispatch(addNumber(num));
},
fetchHomeMultidata() {
dispatch(fetchHomeMultidataAction());
},
};
};
//connect高阶组件负责映射到组件Home
export default connect(mapStateToProps, mapDispatchToProps)(Home);