Redux Hooks actions 调用方式优化(一)

4 篇文章 0 订阅

hooks 可以说是现在react编程的的主流,redux 迎合这个主流也推出 toolkit 工具集来。但是在用toolkit 搭建前端框架后,给人的感觉就是比原先的connect 那一套好些,但用起来还是挺繁琐的。

一 toolkit 搭建的正常使用版本

1.1 创建store

import { configureStore } from '@reduxjs/toolkit'

export const store = configureStore({
  reducer: {},
})

// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch

通过Priovider 绑定到root组件里面

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)

1.2 创建model

通过toolkit 提供的createSlice 来 创建model

import { createSlice } from '@reduxjs/toolkit'
import type { PayloadAction } from '@reduxjs/toolkit'
export interface CounterState {
  value: number
}
const initialState: CounterState = {
  value: 0,
}

export const counterSlice = createSlice({
  name: 'counter',
  initialState,
  reducers: {
   //同步actions 
    increment: (state) => {
      state.value += 1
    },
    decrement: (state) => {
      state.value -= 1
    },
    incrementByAmount: (state, action: PayloadAction<number>) => {
      state.value += action.payload
    },
  },
})

// 分别导出actions
export const { increment, decrement, incrementByAmount } = counterSlice.actions
export default counterSlice.reducer

嵌入到store 里面

export const store = configureStore({
  reducer: {
    counter: counterReducer,
  },
})

1.3 在组件里面使用model 的state 和actions的方式

state 官网推荐useSelector 获取,具体代码如下:

const count = useSelector((state: RootState) => state.counter.value)

actions 官方给的例子是通过import 引入,再通过dispatch 派发

import { useSelector, useDispatch } from 'react-redux'
import { decrement, increment } from './counterSlice'

const dispatch = useDispatch();
dispatch(increment())  // 每个actions 运行都需要用dispatch 派发 
dispatch(decrement())

每个action的运行都需要用dispatch 派发, 如果一个组件使用了10多个action,dispatch 就需要重复出现10多次,明显的代码(dispatch)冗余,这让人有点难受。

二:怎么缩减dispatch出现的次数?

每个action都需要一个dispatch派出,在优化action的dispatch 前,我们先设想下什么样的api 比较理想?有方向才好改代码。
借鉴easy-peasy 库的理念,理想的情况应该是这样的:用useStoreState 获取state,用useStoreActions 获取actions,用到action是直接执行action函数。举个例子:

//组件内引入 useStoreState 、useStoreActions
const { value} = useStoreState((state) => state.counterSlice);
const { increment, decrement, incrementByAmount } = useStoreActions((actions) => actions.counterSlice);

//组件使用action
increment();
decrement();
incrementByAmount(1);

这样看,代码简洁就提升了非常多,也非常方便在组件里面引用。

三、useStoreState 、useStoreActions的具体实现

3.1 创建 生成 useStoreState 和 useStoreActions 的工厂函数

useStoreState 直接等效于useSelector Api ,这里就相关于改变了下命名。

import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
import { AppDispatch, RootState } from './store';

export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
function createTypedHooks() {
  return {
    useStoreState: useAppSelector,
  };
}
const typedHooks = createTypedHooks();
//export const useStoreActions = typedHooks.useStoreActions;
export const useStoreState = typedHooks.useStoreState;

useStoreActions 的实现思路:先获取对应model的action ,然后再在action 外层套上dispatch函数。

import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
import { AppDispatch, RootState, globalDispath} from './store';
import storeModel from '@src/models';
// storeModel.storeModelActions 这里先假设获取能获取对应的model,createStoreActionsHook函数给每个actions套上dispatch
const storeActions = createStoreActionsHook(storeModel.storeModelActions);
const typedHooks = createTypedHooks();
export const useStoreActions = typedHooks.useStoreActions;

//下面是对应的封装函数
function createTypedHooks() {
  return {
    useStoreActions: storeActions,
  };
}
//globalDispath 来自store
type StoreModelActionsType = typeof storeModel.storeModelActions;
function createStoreActionsHook<T extends StoreModelActionsType>(store: T) {
  return <Result extends T[keyof T]>(mapActions: (action: T) => Result) => {
    const storeArr = mapActions(store) as any;
    const obj = Object.keys(storeArr).reduce((prev, v) => {
      return { ...prev, [v]: (...left: any) => globalDispath(storeArr[v](...left)) };
    }, {});

    return obj as Result;
  };
}

顺着这个思路,现在就只剩下storeModel.storeModelActions 怎么获取了。重新改下models的构造,把每个model 的reducer 和actions 单独存放

import counterModelAsync from './counter.model';
const storeModelReducer = {
  counterModel: counterModelAsync.reducer,
};
const storeModelActions = { counterModel: counterModelAsync.actions };
const storeModel = { storeModelReducer, storeModelActions};
export default storeModel;

对应的store 的引用也修改下

import { configureStore } from '@reduxjs/toolkit';
import storeModel from 'src/models';

export const store = configureStore({
  reducer: { ...storeModel.storeModelReducer },
});

export const globalDispath = store.dispatch;
export type AppDispatch = typeof store.dispatch;
export type RootState = ReturnType<typeof store.getState>;

经过这样改造,组件里面就可以实现两个api 就能解决redux store 里面state 和action的使用了。而且能经过ts的类型 。效果如下:
在这里插入图片描述
redux的异步actions 在组件里面怎么使用,是不是也可以使用同样的方式优化?这个下篇文章再讲。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值