frontend icon indicating copy to clipboard operation
frontend copied to clipboard

重构: 拆分Redux store

Open zjsth92 opened this issue 4 years ago • 5 comments

现在的Redux都是集中在https://github.com/cloudreve/frontend/blob/d752e266d52230b3334b88b22facd9f5d37eda9e/src/reducers/index.js#L39 建议可以做几个重构

  1. 拆分Reducer
  2. Action type 添加 Namespace

拆分Reducer

reducers/
- index.js
- siteConfig.js
- navigator.js
- viewUpdate.js
- explorer.js

Action type 添加 Namespace

同时由于Action会越来越多,对单一RedUC而对应的Action加Namespace进行隔离, 比如https://github.com/cloudreve/frontend/blob/220a080a1b8ace8718188420c02d914d8cd2f074/src/actions/index.js#L14-L19 变成

export const drawerToggleAction = open => {
    return {
        type: "viewUpdate/DRAWER_TOGGLE",
        open: open
    };
}

需要多个Reducer同时做出反应的全局Action,保持命名不变。比如 https://github.com/cloudreve/frontend/blob/220a080a1b8ace8718188420c02d914d8cd2f074/src/actions/index.js#L257-L262 需要多个reducer更改State https://github.com/cloudreve/frontend/blob/53aa9ace9689fae06bedc5f6e0db3ae6b9ff9432/src/reducers/index.js#L478-L498

我们需要一个Higher Order Reducer, 读取namespace 将Action分配给对应的Reducer。同时Reducer可以写为 [Action Type]: (state, action) => state 的形式,比如

const viewUpdate = {
    DRAWER_TOGGLE: (state, action) => {
    // 处理DRAWER_TOGGLE
    },
    ...
}

这样的好处

  1. 业务逻辑更清晰
  2. 通过函数的scope 解决变量重复命名问题,现在的switch模式变量不能重复命名,只能用原始的var定义

重构方案

  1. 对现有的reducers/index.js 添加单元测试
  2. 拆分Reducer
  3. Higher Order Reducer , 重构Reducer, 重构Action生成函数
    • 这个Higher Order Reducer 可以自己写也可以找第三方。但是我个人更倾向自己写,因为逻辑并不复杂。自己写代码更清楚,他人提交PR时更容易看懂。降低学习曲线。

好处

可以更轻松支持分页这种更复杂的UI逻辑 https://github.com/cloudreve/frontend/issues/12

zjsth92 avatar Apr 30 '20 07:04 zjsth92

感谢建议! 可能要到3.1版本那边的计划实现的差不多后才有时间开始进行重构。

HFO4 avatar Apr 30 '20 08:04 HFO4

我下周有空可以写单元测试

zjsth92 avatar Apr 30 '20 15:04 zjsth92

@zjsth92 是否考虑这样的拆分方式:

关于 redux

Redux 整体设计采用 Ducks

state

State 设计遵循以下原则(数据库设计原则):

  • 数据按照领域(Domain)分类,存储在不同的表中,不同的表中存储的列数据不能重复。
  • 表中每一列的数据都依赖于这张表的主键。
  • 表中除了主键以外的其他列,互相之间不能有直接依赖关系。

目录结构分配

// 仅供参考, 这里以我的项目为基准
redux/
- ducks
  - user.ts
  - article.ts
  - comment.ts
- reducers.ts
- store.ts

store.ts:

import { createStore } from 'redux';
import reducers from './reducers';

export default createStore(reducers);

reducers.ts:

// reducer 入口
import { combineReducers } from 'redux';
import user from './ducks/user';
import comment from './ducks/comment';
import article from './ducks/article';

// combineReducers
export default combineReducers({user, comment, article});

user.ts:

// Actions
export const types = {
    LOGIN: 'userLogin', // 登录
    LOGOUT: 'userLogout', // 登出
    UPDATE: 'userUpdate', // 更新信息
    COMMENT: 'comment', // 评论, 大概率移除
    PUBLISH: 'publish', // 发布, 大概率移除
};

// state
const initialState: State = {
    id: '', // key
    bio: '',
    url: '',
    nickname: '',
    username: '',
    position: '',
    isLogin: false,
};

// Reducer
export default function reducer(state = initialState, action: Action = {}) {
    const { payload } = action;
    switch (action.type) {
        case types.LOGIN:
            return Object.assign({}, state, payload);
        case types.LOGOUT:
            return Object.assign({}, state, initialState);
        case types.UPDATE:
            return Object.assign({}, state, payload);
        case types.COMMENT:
            return Object.assign({}, state);
        case types.PUBLISH:
            return Object.assign({}, state);
        default:
            return state;
    }
};

// Action creaters
export const actions = {
    userLogin: (payload: Payload) => ({ type: types.LOGIN, payload }),
    userLogout: () => ({ type: types.LOGOUT }),
    userUpdate: (payload: Payload) => ({ type: types.UPDATE, payload }),
    // 文章id 评论内容 content
    userComment: (payload: Payload) => ({ type: types.COMMENT, payload }),
    // 文章title 文章内容 content
    userPublish: (title: string, content: string) => ({ type: types.PUBLISH, payload: { title, content } }),
};

这样方便默认导出 reducer, 同时可以快速的通过 import { actions } from 'xxxx' 的形式拿到单独的 action creater

BadmasterY avatar May 06 '20 06:05 BadmasterY

  1. Duck模式可以的。
  2. 新代码写成TS也可以
  3. 重构State目前不太现实,改动太大了只能一点点改。

zjsth92 avatar May 06 '20 17:05 zjsth92

Why not consider importing Redux Toolkit?

AH-dark avatar Dec 21 '22 04:12 AH-dark