Redux Toolkit: React的官方状态管理工具/rtk

在标准 rtk 的基础上封装
更新于: 2024-07-27 08:49:43

安装

yarn add @reduxjs/toolkit react-redux

架构

redux-toolkit-notes/src/stores on 🌱 main [!] via 🐠 v20.8.0
$ tree
.
├── index.ts
└── modules
    ├── app.ts
    ├── counter.ts
    └── user.ts

其中一个 slice,即 业务的 store

import { createSlice } from '@reduxjs/toolkit';

export default createSlice({
  name: 'user',
  initialState: {
    token: null,
    profile: null
  },
  reducers: {
    // nx.$dispatch({ type: 'user/setToken', payload: 'xxxx'})
    setToken: (state, action) => {
      state.token = action.payload;
    },
    setProfile: (state, action) => {
      state.profile = action.payload;
    }
  },
  extraReducers: (builder) => {
    builder.addMatcher(
      (action) => action.type === 'user/setProfile',
      (state, action) => {
        localStorage.setItem('profile', JSON.stringify(action.payload));
      }
    );
  }
});

nx套件

自己基于 redux-tookit 的2次封装,方便在项目中使用。

名称功能及用法
nx.$use
// 对应 useSelector 的 hook,传入 path 取得值,只能当 hook 使用
nx.$use('user.token');
nx.$get
// 取得 store.getState() 中的值,用法同 nx.$use,但可以使用在非 hook 场景
nx.$get('user.token');
nx.$patch
// 同 dispatch
nx.$patch({ type: 'xx', payload: 'yyy' })
nx.$patch(type, payload);
nx.$call
nx.$call('user/setProfile', { name: 'aric' })

rtk-state-tree

一个原理性的实现。

import { configureStore } from '@reduxjs/toolkit';
import { useSelector } from 'react-redux';
import { scanVite } from '@jswork/scan-modules';

const moduleFiles = import.meta.glob('./modules/**/*.ts', { eager: true });
const stores = scanVite(moduleFiles, { modules: '/modules/' });
const reducer = Object.keys(stores).reduce((acc, key) => {
  const { name, reducer } = stores[key];
  return { ...acc, [name]: reducer };
}, {});

const rootStore = configureStore({ reducer });

function useNxSelect(path: string, defaults?) {
  return useSelector((state) => nx.get(state, path, defaults));
}

nx.$rootStore = rootStore;
nx.$get = (path: string, defaults?) => nx.get(rootStore.getState(), path, defaults);
nx.$use = useNxSelect;
nx.$patch = rootStore.dispatch;
nx.$call = (type: string, payload?) => {
  let result;
  Object.keys(stores).forEach((key) => {
    const { actions } = stores[key];
    let action;
    Object.keys(actions).forEach((key) => {
      const item = actions[key];
      if (item.type === type) {
        action = item;
      }
    });

    if (action) {
      result = rootStore.dispatch(action(payload));
    }
  });
  return result;
};

export default rootStore;

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

参考