介绍
使用过React的人,一定对Redux这个Javascript状态容器很熟悉,就算后面React官方提供了React的绑定库React-Redux,依然没有解决代码冗余,依赖过多的问题,给开发者带来不少学习跟开发成本。于是乎,Redux-Toolkit这个库横空出世,成为最新的状态管理的标准,并致力于解决以下三个难题。
- "Configuring a Redux store is too complicated" 配置Redux复杂
- "I have to add a lot of packages to get Redux to do anything useful" 安装依赖过多
- "Redux requires too much boilerplate code" 样板代码过多
基于官网的Create-React-App的TypeScript项目,给各位介绍一下如何实现Redux-Toolkit,关于更复杂一点的中间件的实现会在下一篇文章讲述。
步骤
安装依赖
npm install @reduxjs/toolkit react-redux
在Reactv7.2.3之后,react-redux已包含@types/react-redux,如果是低版本,需手动安装@types/react-redux
定义Store对象,以及输出 获取参数getState,获取方法dispatch的类型
在Src下新建一个文件夹store, 在里面新增一个入口文件index.ts,其中在index.ts中引入各个模块。
import { configureStore } from '@reduxjs/toolkit'
import counterSlice from './slice/counterSlice'
export const store = configureStore({
// 每个reducer代表一个模块的状态管理器
reducer: {
counter: counterSlice // 在组件里通过state.counter来获取counterSlice这个模块
}
})
// RootState作用是返回store的方法getState的类型 function
export type RootState = ReturnType<typeof store.getState>
// AppDispatch 作用是拿到Store的dispatch方法的类型 function
export type AppDispatch = typeof store.dispatch
定义类型的Hook
为避免每次引入Redux的组件还要注册类型(state: RootState),在store下新建一个hook.ts文件,把type跟获取参数or操作的方法结合并封装起来。同时可避免出现潜在的循环引入依赖的问题。
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import type { RootState, AppDispatch } from './index'
// use hook 节约每次引入type的工作
// useSelector: 节约配置RootState type
export const useAppDispatch = () => useDispatch<AppDispatch>()
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
新增一个状态管理模块Slice
在store下新增一个slice文件夹,用于存在不同的状态管理模块,每个模块负责管理不同的功能或者页面。 新增文件counterSlice.ts,把状态初始值跟方法定义好,最终export出去。
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
import type { RootState } from '@/store/index'
// 定义 CounterState 的type
interface CounterState {
value: number // 规定value必须是number型
}
// 定义 初始state
const initialState: CounterState = {
value: 0
}
export const counterSlice = createSlice({
name: 'counter',
initialState, // 状态管理state
reducers: { // 操作state
increment: (state) => {
state.value += 1
},
decrement: (state) => {
state.value -= 1
},
// Use the PayloadAction type to declare the contents of `action.payload`
// PayloadAction 规定输入的类型,此为number类型
incrementByAmount: (state, action: PayloadAction<number>) => {
state.value += action.payload
}
}
})
export const { increment, decrement, incrementByAmount } = counterSlice.actions
export const selectCount = (state: RootState) => state.counter.value
export default counterSlice.reducer
组件引入Slice
最终在组件里引入redux,官方建议使用已经定义过类型的hook而不是标准的hook。 在Page文件夹下增加Counter.tsx,使用store/hook 定义的useAppDispatch, useAppSelector去获取状态跟方法。从截图可以看出来已经实现了很简单的一个计数器功能,接下来只需要在每个slice中新增不同的模块,给相对应的组件调用hook跟slice里面的方法就可简单管理状态了。
import { useAppDispatch, useAppSelector } from '@/store/hook'
import { increment, decrement } from '@/store/slice/counterSlice'
export default function Counter() {
const { value } = useAppSelector((state) => state.counter) // state获取了所有的模块,这里取其中的counter
const dispatch = useAppDispatch() // 用以调用不同模块中的方法
return (
<div>
<button
onClick={() => {
dispatch(increment())
}}
>
{value}
</button>
<hr />
<button
onClick={() => {
dispatch(decrement())
}}
>
{value}
</button>
</div>
)
}