【react框架】告别过去,现在的react-redux状态管理库既好理解又好用!

前言

React的状态管理库一开始是个第三方库,叫做Redux。

后来Facebook发现这个库的使用量很大,于是官方就也出了个功能一样的库叫做react-redux。

这就是原本Redux和react-redux的关系。

我之前使用过类组件时期的Redux、函数组件初期的Redux,发现都特别难用,哪些简化Redux理解和操作的第三方库也不是那么好用。

对应的调试工具还是类似vsconsole那种入侵代码的库。

整体和当时的VueX对比,使用体验还是差很多的。

如今的react-redux(不知道是从哪一代更新的)变得异常好用,而且使用方式简化好多,也好理解,并且有浏览器插件的调试工具。已经完全不需要用第三方的了。


store、actions、reducers概念

以下是我对这三者的理解,但还停留在类组件时期,不知道现在的意思有没有变化(有空再去官网瞅瞅)。

  • store:是redux的指挥中心,接收actions发过来的任务,安排给reducers去执行。

  • actions:可以理解为这个人就是一个传话筒,负责接收到组件派发的任务后通知store,每个任务的通知是一个对象的形式,内部有type字段用来标记要做的是什么事,data字段用来存放需要的数据。

  • reducers:他负责执行store给的任务,并把最新的state给返回给store,store再把数据传递给组件。

看完我的大白话描述是不是对这些概念就清晰很多了。


使用

使用方式直接看 官方网址 ,建议直接从教材那一栏开始看起。非常简单:

在这里插入图片描述


一些简化思路

state获取简化

获取store中某个值其实封装成一个hook更好,利于复用和阅读,直接在redux的文件夹创建一个hooks文件,然后写入hook,官方推荐了一个写法:

import { TypedUseSelectorHook, useSelector } from "react-redux";
import type { RootState } from "@/redux/index";

// 在整个应用程序中使用,而不是简单的 `useDispatch` 和 `useSelector`
const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
export default useAppSelector;

使用:

const value = useAppSelector((state) => state.global.value);

感觉好处就是不需要每次获取state的时候传入TS类型。

我也来推荐一个自己发现的更好方法,例如获取store里的pageInfo对象数据:

import { useSelector } from 'react-redux'
import type { StateType } from '../store'
import type { PageInfoType } from '../store/pageInfoReducer' // 某个redux模块

function useGetPageInfo() {
  const pageInfo = useSelector<StateType>(state => state.pageInfo) as PageInfoType
  return pageInfo
}

export default useGetPageInfo

获取直接这样:

const { title } = useGetPageInfo()

reducer调用简化

同样官方也推荐了个写法:

import { useDispatch } from "react-redux";
import type { AppDispatch } from "@/redux/index";

// 在整个应用程序中使用,而不是简单的 `useDispatch` 和 `useSelector`
const useAppDispatch: () => AppDispatch = useDispatch;
export default useAppDispatch;

但使用起来和原来没太大区别,所以可以这样写,先在Redux的主入口写:

import { configureStore } from "@reduxjs/toolkit";
import global from "./global";

const store = configureStore({
  reducer: {
    global,
  },
});

export default store;

// 从 store 本身推断出 `RootState` 和 `AppDispatch` 类型
export type RootState = ReturnType<typeof store.getState>;
// 最主要的是这个
export type AppDispatch = Pick<
  ReturnType<typeof store>,
  "dispatch"
>["dispatch"];

然后写个hooks:

import { useDispatch } from "react-redux";
import { Slice } from "@reduxjs/toolkit";
import { AppDispatch } from "../redux/index";

type GetArrFirst<T> = T extends [infer Res] ? Res : unknown;

const useAppDispatch = () => useDispatch<AppDispatch>();

const useCreateReduxFunction = <S extends Slice>(slice: S) => {
  return <T extends keyof S["actions"]>(name: T) => {
    const dispatch = useAppDispatch();
    const actionCreator = (slice.actions as S["actions"])[name];
    return (payload?: GetArrFirst<Parameters<typeof actionCreator>>) => {
      dispatch(actionCreator(payload));
    };
  };
};
export default useCreateReduxFunction;

然后在模块中包裹下Slice:

export const useGlobalReduxFunction = createReduxFunction(GlobalSlice);

然后我们就能轻松调用这个模块的reducer了:

const setCurrentAssistant = useGlobalReduxFunction('setCurrentAssistant');

一个模块的reducer被执行后同时修改另一个模块的state

目前发现个不错的写法,例如我有个叫agentSlice的模块里面有个aaa方法要修改globalSlice模块里的某个state变量bbb,可以做如下步骤。

首先在agentSlice导出agentSlice的reducer:

export default agentSlice.reducer;

然后在globalSlice中引入:

import { agentSlice } from '../agent/index';

并且在reducer同级后加个:

extraReducers(builder) {
	builder.addCase(
		agentSlice.actions.aaa,
		(state, action) => {
			state.bbb= action.payload;
		}
	);
},

react-redux调试工具(推荐)

安装浏览器插件Redux DevTools,控制台就能看到了,可以自行百度下~


用immer改善编码体验(必装)

我们知道reducer执行里如果要修改store,需要返回一个新的store,就和写setState一样,有时候挺麻烦的。可以借助immer第三方工具库改成和Vue一样直接改写的编码风格。

例如:

import { createSlice, PayloadAction } from '@reduxjs/toolkit'
import produce from 'immer'

export type UserType = {
    id?: string
    user?: string
}

// 假设初始值
const UserTypeState: UserType = {
	id: '1',
	user: 'admin'
}

export const userInfoSlice= createSlice({
    name: 'userInfo', // 模块名称
    initialState: UserTypeState, // 设置初始state数据
    reducers: { // 设置reducer
        changeUserName : produce((draft: UserTypeState, action: PayloadAction<{ userName: string }>) { // produce包一层
            draft.user = action.payload // 直接修改即可
        }),
    }
})

export const { changeUserName } = userInfoSlice.actions // 把要用到的actions都导出去

export default userInfoSlice.reducer // 导出的是reducer

这个draft是个引用类型,从它那里解构出来的变量直接修改了也是生效的


借助redux-undo实现撤销重做(推荐)

如果以后产品和你说要实现撤销重做功能,一定要第一时间想到redux-undo这个库。

在汇合文件index.js中,假设有个模块edit,负责某个编辑功能:

import { configureStore } from '@reduxjs/toolkit'
import userInfo, { UserType } from './userInfo.js'
import EditInfo, { EditType } from './edit.js'

// 所有state汇合起来
export type StateType = {
    userInfo: UserType
    editInfo: EditType 
}

export default configureStore({
    reducer: {
        userInfo,
        // 扩展其他模块
        editInfo
    }
})

edit模块的很多操作都写在了redux对应的模块中,咱们需要对这个edit模块的操作添加上撤销重做的特性。加入redux-undo可以改写成这样:

import { configureStore } from '@reduxjs/toolkit'
import userInfo, { UserType } from './userInfo.js'
import editInfo, { EditType } from './edit.js'
import undoable, { excludeAction, StateWithHistory } from 'redux-undo'

// 所有state汇合起来
export type StateType = {
    userInfo: UserType
    editInfo: StateWithHistory<EditType> // 1 泛型包裹一下 
}

export default configureStore({
    reducer: {
        userInfo,
        // 包裹
        editInfo:undoable(editInfo, {
	      limit: 20, // 限制 undo 20 步
	      filter: excludeAction([ // 这里是过滤哪些reducer操作不需要加撤销重做功能,每项格式为: 文件地址+ /actions名称
	        'edit/resetComponents',
	        'edit/changeSelectedId',
	        'edit/selectPrevComponent',
	        'edit/selectNextComponent',
	      ]),
	    })
    }
})

在别的地方只需要这样调用即可撤销重做:

import { ActionCreators as UndoActionCreators } from 'redux-undo'
import { useDispatch } from 'react-redux'

const dispatch = useDispatch()

// 撤销
function undo() {
  dispatch(UndoActionCreators.undo())
}

// 重做
function redo() {
  dispatch(UndoActionCreators.redo())
}

获取store要多拿一个值present

const pageInfo = useSelector<StateType>(state => state.pageInfo.present) as PageInfoType

尾巴

建议看完后再去官网上学习下,更全面的了解Redux。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值