是什么
redux-toolkit 是redux官方封装和标准化的工具集,其主要作用是简化redux状态库的创建和使用。它内置了Immer、redux-thunk和reselect。redux-toolkit为我们做了下面这些事情:
- 简化store创建
- 简化reducer创建
- 简化不可变更新的实现
- 内置常用中间件,简化设置常用中间件的逻辑代码
- 自动生成action生成函数,简化action创建
- dispatch异步逻辑标准化
怎么用
redux-toolkit的基本使用:
起始于两个关键API来简化Redux应用中一些公共的操作
configureStore:简化store的创建,自动组合reducer、添加常用中间件。
createSlice:简化reducer的创建,集成Immer库,避免使用扩展运算实现不可变更新。通过slice name和reducer name创建action生成器。
jsx
//创建reducer
const initialState = {
userName: "张三",
signature: "早"
}
//创建userSlice
const userReducer = createSlice({
name: 'user', // 切片名称
initialState, // 初始状态
reducers: { // 定义reducer函数,用于处理action
setUserName: (state, action) => {
state.userName = action.payload
},
setSignature: (state, action) => {
state.signature = action.payload
}
}
})
//创建store
const store = configureStore({
reducer: {
user: userReducer.reducer,
product: productReducer.reducer,
},
});
从基本使用可以看出:
- redux-toolkit简化了reducer的创建,不需要大量的switch case语句控制reducer流程,它内部进行处理。
- redux-toolkit会根据reducer配置创建同名action生成器并挂载到slice对象的actions属性下。通过调用action生成器,其内部会绑定对应的type,传入生成器的数据挂载到action.payload上。
- 在reducer中,我们可以看到这样的代码
state.userName = action.payload
,这意味着不需要通过扩展运算符来保证不可变更新。 - 所以redux-toolkit简化了reducer和action创建的样板代码。
- slice还提供了其他的Api,比如selectSlice、getSelectors这些状态访问器,这些我们在结合react-redux使用时再介绍。
高级用法
- store增强。内置Redux DevTools集成工具
- 中间件。内置redux-thunk、Serializable State Invariant(开发环境)、Immutable State Invariant(开发环境)
这里主要介绍redux-toolkit中如何配置增强器和中间件以及redux-thunk中间件的作用、实现原理及其扩展。
-
如何在redux-toolkit中配置中间件和增强器
jsxconst store = configureStore({ reducer: { user: userReducer.reducer, product: productReducer.reducer, }, middleware: (getDefaultMiddleware) => { //获取默认中间件 const middleware = getDefaultMiddleware(); return middleware.concat(yourMiddleware); }, enhancers: (getDefaultEnhancers) => { //获取默认增强器 const enhancers = getDefaultEnhancers(); //返回 return enhancers.concat(yourEnhancers); }, });
middleware和enhancers配置项接收一个回调函数,并将getDefaultMiddleware和getDefaultEnhancers传递给回调函数,这两个方法默认获取内置的所有增强器和中间件,也可根据传入的配置获取特定的中间件。configureStore根据middleware和enhancers配置返回的结果创建增强器和中间件。
-
redux-thunk的作用和原理
redux-thunk是一个中间件,它提供dispatch 函数类型action的代码执行机制(默认情况下,action是一个对象)。当action是一个函数时,则执行这个函数。其实现原理如下:
jsxfunction thunkMiddleware({ dispatch, getState }) { return (next) => (action) => { if (typeof action === "function") { return action(dispatch, getState); } return next(action); }; }
为什么需要创建这种机制?在Redux中,如果要在dispatch到reducer的过程中执行一些额外的逻辑时,需要通过中间件来插入,但是中间件的弊端是,在每次dispatch时,所有的中间件都会执行。这种机制在某些场景中就显得不太适用,所以通过dispatch函数类型的action,让我们在需要的时候才执行额外的代码逻辑,我们称这些特定的代码为thunk。
-
createAsyncThunk
createAsyncThunk是为redux-thunk针对异步thunk的创建而设计,规范异步thunk的执行流程,简化异步thunk的代码组织。createAsyncThunk的使用和基本原理如下:
jsx//基本实现 function createAsyncThunk(typePrefix, payloadCreator) { //返回actionCreator函数 return (thunkArgs) => { //获取dispatch函数 return (dispatch, getState) => { (() => { //调用payloadCreator函数,获取异步操作的结果 const result = await payloadCreator(thunkArgs, { dispatch, getState }) //根据异步操作的结果,dispatch不同的action if (result) { dispatch({ type: `${typePrefix}/fulfilled`, payload: result }) } else { dispatch({ type: `${typePrefix}/rejected` }) } })() } } } //创建asyncThunk const fetchUserInfo = createAsyncThunk( 'user/fetchUserInfo', async (userId, thunkAPI) => { console.log(userId, thunkAPI) const response = await new Promise((resolve, reject) => { setTimeout(() => { resolve("李四") }, 1000); }); // const data = await response.json(); return response; } ); //createAsyncThunk会自动创建padding、fulfilled、rejected状态的action,并在对应状态时dispatch,所以需要在slice上对原reducer进行扩展 const userReducer = createSlice({ name: 'user', // 切片名称 initialState, // 初始状态 reducers: { // 定义reducer函数,用于处理action setUserName: (state, action) => { state.userName = action.payload }, setSignature: (state, action) => { state.signature = action.payload } }, extraReducers(builder) { builder.addCase(fetchUserInfo.fulfilled, (state, action) => { console.log(action) state.userName = action.payload }) builder.addCase(fetchUserInfo.rejected, (state, action) => { state.userName = "张三" }) builder.addCase(fetchUserInfo.pending, (state, action) => { state.userName = "加载中..." }) }, }) //在UI中使用 function UserInfo() { function handleClick() { store.dispatch(fetchUserInfo(1)); } return( <> <h1>用户信息</h1> <div>姓名: 张三</div> <button onClick={handleClick}>修改姓名</button> </> ) }
-
定制action的payload。在某些情况下,我们需要对payload做一些统一处理时,需要将这些统一处理逻辑集中处理(数据校验、添加公共属性等)。createSlice在配置中实现了这一机制。通过改造reducers配置项,把需要处理的reducer改为一个对象,对象包含reducer和prepare。dispatch时,先执行prepare对payload统一处理后再创建action。需要注意的是,prepare回调函数必须返回带有payload属性的对象。使用如下:
javascriptconst userReducer = createSlice({ name: 'user', // 切片名称 initialState, // 初始状态 reducers: { // 定义reducer函数,用于处理action //将reducer配置成对象 setUserName:{ reducer: (state, action) => { state.userName = action.payload }, //payload预处理 prepare: (userName) => { //必须返回带有payload属性的对象 return { payload: userName } } }, setSignature: (state, action) => { state.signature = action.payload } }, })
总结:redux-toolkit对redux状态管理库从创建到使用进行了一些列的封装和扩展,内置常用功能扩展库和样板代码的处理逻辑。让开发者通过更少的代码实现更强大的状态管理模块。redux-toolkit的整体还是围绕reducer、action、select、store增强和中间件几大核心进行封装,提供dispatch异步逻辑处理规范等。本文中还有许多细节问题没有展开讨论,但已经包含了redux-toolkit的核心内容和使用场景。