React-Redux 的 Redux-Toolkit 你用了吗

1,807 阅读3分钟

介绍

使用过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中引入各个模块。

image.png

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>
  )
}

image.png image.png