Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

重构: 拆分Redux store #17

Open
zjsth92 opened this issue Apr 30, 2020 · 5 comments
Open

重构: 拆分Redux store #17

zjsth92 opened this issue Apr 30, 2020 · 5 comments
Labels
enhancement New feature or request

Comments

@zjsth92
Copy link
Contributor

zjsth92 commented Apr 30, 2020

现在的Redux都是集中在

const cloudreveApp = (state = [], action) => {

建议可以做几个重构

  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进行隔离, 比如

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

变成

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

需要多个Reducer同时做出反应的全局Action,保持命名不变。比如

export const searchMyFile = keywords => {
return {
type: "SEARCH_MY_FILE",
keywords: keywords
};
};

需要多个reducer更改State
case 'SEARCH_MY_FILE':
return Object.assign({}, state, {
navigator: Object.assign({}, state.navigator, {
path: "/搜索结果",
refresh:state.explorer.keywords === null? state.navigator.refresh:!state.navigator.refresh,
}),
viewUpdate:Object.assign({}, state.viewUpdate, {
contextOpen:false,
navigatorError:false,
navigatorLoading:true,
}),
explorer:Object.assign({}, state.explorer, {
selected:[],
selectProps: {
isMultiple:false,
withFolder:false,
withFile:false,
},
keywords:action.keywords,
}),
});

我们需要一个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逻辑 #12

@HFO4 HFO4 added the enhancement New feature or request label Apr 30, 2020
@HFO4
Copy link
Member

HFO4 commented Apr 30, 2020

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

@zjsth92
Copy link
Contributor Author

zjsth92 commented Apr 30, 2020

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

@BadmasterY
Copy link

BadmasterY commented May 6, 2020

@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

@zjsth92
Copy link
Contributor Author

zjsth92 commented May 6, 2020

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

@AH-dark
Copy link
Contributor

AH-dark commented Dec 21, 2022

Why not consider importing Redux Toolkit?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants