使用普通的Redux写法的缺点:代码量过多,不利于管理,编写逻辑过于的繁琐和麻烦。Redux-Toolkit 是官方推荐的编写 Redux 逻辑的方法。
安装:
npm install @reduxjs/toolkit react-redux
1.Redux-Toolkit核心的API
- configureStore:
用于创建store对象。包装createStore以提供简化的配置选项和良好的默认值。可以自动组合划分的reducer,还可以添加我们自己提供的任何 Redux 中间件。其中redux-thunk默认包含,并自动启用 Redux DevTools Extension。
-
reducer:将slice中的reducer可以组成一个对象传入此处
-
middleware:可以使用参数,传入其他的中间件
-
devTools:是否配置devTools工具,默认为true
-
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from './features/counter'
const store = configureStore({
reducer: {
counter: counterReducer
}
})
export default store
- createSlice:接受reducer函数的对象、切片名称和初始状态值,并自动生成切片reducer,并带有相应的actions。createSlice主要包含如下几个参数:
-
name:用户标记slice的名词
-
initialState:第一次初始化时的值
-
reducers:相当于之前的reducer函数,对象类型,并且可以添加很多的函数。函数其实相当于redux写法的reducer中的一个case语句。函数中有两个参数:1.state,state的旧值;2.调用这个action时,传递的action参数。
-
createSlice返回一个对象,该对象包含所有的action和一个reducer
import { createSlice } from "@reduxjs/toolkit";
const counterSlice = createSlice({
name: 'counter',
initialState: {
counter: 888
},
reducers: {
addNumber(state, { payload }) {
state.counter += payload
},
subNumber(state, { payload }) {
state.counter -= payload
}
}
})
export const { addNumber, subNumber } = counterSlice.actions
export default counterSlice.reducer
2.Redux-Toolkit的异步操作
使用redux进行异步操作的时候我们需要使用redux-thunk中间件。现在Redux Toolkit默认已经继承了redux-thunk中间件,并暴露了一个函数createAsyncThunk。
createAsyncThunk函数创建出来的action被dispatch出来时有三个状态:
-
pending:action被发出,但是还没有最终的结果;
-
fulfilled:获取到最终的结果(有返回值的结果);
-
rejected:执行过程中有错误或者抛出了异常;
基本使用:
createAsyncThunk函数的第二个参数接收一个回调函数,该回调函数可传入两个参数,第一个是调用dispatch时,传入的一些数据,第二个是创建的store,我们可以在store中拿到dispatch调用reducer。也可以通过extraReducers来监听状态进而改变state值。
export const getHomeMultidataAction = createAsyncThunk('home/multidata', async (params, store) => {
const res = await axios.get('http://xxx')
return res.data
})
dispatch后返回三种状态
const mapDispatchToProp = (dispatch) => ({
getHomeMultidata() {
dispatch(getHomeMultidataAction(null))
}
})
然后我们可以在createSlice的extraReducers中监听这些结果。
常用的方式:
extraReducers: {
[getHomeMultidataAction.pending](state, action) {
console.log('getHomeMultidataAction pending', action);
},
[getHomeMultidataAction.fulfilled](state, action) {
console.log('getHomeMultidataAction fulfilled', action);
// 修改state的值,可直接复制修改,不需要重新返回一个对象
},
[getHomeMultidataAction.rejected](state, action) {
console.log('getHomeMultidataAction rejected', action);
}
},
第二种方式:
extraReducers(builder) {
builder.addCase(getHomeMultidataAction.pending, (state, { payload }) => {
console.log('getHomeMultidataAction pending', payload);
}).addCase(getHomeMultidataAction.fulfilled, (state, { payload }) => {
console.log('getHomeMultidataAction fulfilled', payload);
})
}
第三种方式:
export const getHomeMultidataAction = createAsyncThunk('home/multidata', async (params, store) => {
const res = await axios.get('http://xxx')
store.dispatch(homeSlice.actions.changeBannersAction())
store.dispatch(homeSlice.actions.changeRecommendsAction())
return res.data
})
注意:使用react-reducer修改state值时,需要返回一个全新的对象,但是在Redux-Toolkit中,我们可以直接通过赋值来修改。下面则是直接可以赋值的原因。
3.Redux-Toolkit的数据不可变性
原理:它并不是通过浅拷贝的方式来完成修改值的操作,使用浅拷贝的方式时当遇到过大的对象,进行浅拷贝也会造成性能的浪费;还有浅拷贝后的对象,在深层改变时,依然会对之前的对象产生影响。 事实上Redux Toolkit底层使用了immerjs的一个库来保证数据的不可变性,当数据被修改时,会返回一个对象,但是新的对象会尽可能的利用之前的数据结构而不会对内存造成浪费;