likes
comments
collection
share

使用「Redux Toolkit」简化redux操作

作者站长头像
站长
· 阅读数 15

前言

使用redux-toolkit能够简化创建redux的流程和代码量,主要通过使用createReducercreateSlice这两个函数让我们轻松管理redux的状态,同时在中间件中默认配置了thunk,不需要额外安装redux-thunk等中间件。

简介

RTK致力于解决如下三个问题

  • "配置一个 Redux store 过于复杂"
  • "做任何 Redux 的事情我都需要添加很多包"
  • "Redux 需要太多的样板代码" RTK包含主要如下的Api

configureStore

包装 createStore 以提供简化的配置选项和良好的默认预设。它可以自动组合你的切片 reducers,添加您提供的任何 Redux 中间件,默认情况下包含 redux-thunk ,并允许使用 Redux DevTools 扩展。

createReducer

为 case reducer 函数提供 action 类型的查找表,而不是编写switch语句。此外,它会自动使用immer 库来让您使用普通的可变代码编写更简单的 immutable 更新,例如 state.todos [3] .completed = true 

createAction

为给定的 action type string 生成一个 action creator 函数。函数本身定义了 toString(),因此它可以用来代替 type 常量。

createSlice

这个createSlice函数,在我看来是RTK中的核心api,官方文档中对它的描述是这样的:该函数接收一个初始化state对象,和一个reducer对象,它可以将store以slice的方式分割成为不同的部分,每个部分都会独立生成相对应的actionstate对象。在99%的情况下,我们都不会直接使用createReducercreateAction,取而代之的就是createSlice

createAsyncThunk

用来处理异步操作的方法,对于使用RTK的项目来说,完成异步操作主要分三个步骤,createAsyncThunk方法主要用来创建异步函数,创建完毕之后在reduce中进行处理,最后在业务代码中用dispatch进行调用,基本流程和标准的Redux并无二致。(需要注意的是,在createSlice中,我们不可以用普通的reduce处理异步函数,必须使用 extraReducers来处理异步)

createEntityAdapter

生成一组可重用的 reducers 和 selectors,以管理存储中的规范化数据

createSelector

来自 Reselect 库,为了易用再导出。

使用

安装

yarn add @reduxjs/toolkit

configueStore 创建图书馆

//index.js
import { configureStore } from "@reduxjs/toolkit"
export default configureStore({
    reducer: {
        // 各个模块
    },
})

configuleStore我们可以比喻为一个图书馆,在图书馆建好之后,我们需要放入图书,但是也不能乱放,我们按照图书分类放置,而分类中每一类在redux中我们称之为slice切片

slice 图书分类

slice我们可以比喻为图书的分类,Slice Reducer切片 其实就是类似于vuex中的 module模块,也就是把图书按种类放在对应的书架上,方便放也方便找!

我们通过createSlice创建切片

import { createSlice } from "@reduxjs/toolkit"

export const slice = createSlice({
    name: "someOne",
    initialState: {
        character: "shy",
    },
    reducers: {
        setActiveDate: (state, action) => {
            state.character = action.payload
        },
    },
})

export const { setActiveDate } = slice.actions
export default slice.reducer

在这里我们创建了一个切片,里面的initalState是初始值,但是还涉及到两个概念reduceraction

Reducer 图书管理员

Reducer我们可以理解为图书馆管理员,存放图书,借书,修改图书都需要经过它的手 Reducer有以下几个特点:

  • 仅使用 state 和 action 参数计算新的状态值'

  • 禁止直接修改 state。必须通过复制现有的 state 并对复制的值进行更改的方式来做 不可变更新(immutable updates)

  • 禁止任何异步逻辑、依赖随机值或导致其他“副作用”的代码

  • Reducer是一个纯函数

action 图书馆借书卡

action在代码中表现为一个具有type字段的javascript对象

const getHerInfo = {
    type: 'CHARACTER'
}

const descripeHer = {
    type: 'CHARACTER',
    payload: 'so cool'
}

Reducer图书馆管理员 只能根据组件传入的 action借书卡 基于当前的图书执行指定操作

useSelector 图书馆电脑

通过图书馆电脑我们能查到我们的借书信息

React组件使用 useSelector 钩子从 store 读取数据

选择器函数接收整个 state 对象,并且返回需要的部分数据

每当Redux store 更新时,选择器将重新运行,如果它们返回的数据发生更改,则组件将重新渲染

useDispatch

useDispatch相当于我们把图书还给图书管理员Reducer

import { useDispatch } from "react-redux"
//...
const dispatch = useDispatch()
const setCharacter = (cha) => dispatch(descripeHer(cha))

onClick={() => {
      setCharacter('so cool')
}}

immutable:不可变

不管是react或者我们的redux,都会提到这样一个关键词immutable,指的是我们不应该直接去修改数据,需要把数据复制一份在去修改,如果react判断到数据改变了,就会re-render,但是如果我们直接把数据修改了,他就无法判断数据的新旧了,导致一个初学者容易遇到的问题,数据修改了组件却没有重新渲染

从代码层面来说,js的数组和对象都属于引用类型,这样就导致我们没办法判断一个新数据与一个旧数据 是否不同,这一点在 react或者是vue的响应式 实现中都是容易踩坑的。

以下是官方文档中提到的不能在 Redux 中更改 state 几个原因:

  • 它会导致 bug,例如 UI 未正确更新以显示最新值
  • 更难理解状态更新的原因和方式
  • 编写测试变得更加困难
  • 它打破了正确使用“时间旅行调试”的能力 在使用 createSlice() 这个api创建切片时,我们传入的参数reducers属性中使用的方法可以直接修改state,因为createSlice` 内部使用了一个名为 Immer 的库,帮助我们将更新转换为不可变更新,这样就方便很多啦~

总结

如果工作中使用的是redux,那我们应该会配上redux-toolkit,感觉可以减少开发的负担,但是现在用的是mobx,总之多了解一下其它的库对我们是比较有利的,下一篇文章大概会去深入了解下mobx.