frontend
frontend copied to clipboard
重构: 拆分Redux store
现在的Redux都是集中在https://github.com/cloudreve/frontend/blob/d752e266d52230b3334b88b22facd9f5d37eda9e/src/reducers/index.js#L39 建议可以做几个重构
- 拆分Reducer
- 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
},
...
}
这样的好处
- 业务逻辑更清晰
- 通过函数的scope 解决变量重复命名问题,现在的
switch
模式变量不能重复命名,只能用原始的var
定义
重构方案
- 对现有的reducers/index.js 添加单元测试
- 拆分Reducer
- Higher Order Reducer , 重构Reducer, 重构Action生成函数
- 这个Higher Order Reducer 可以自己写也可以找第三方。但是我个人更倾向自己写,因为逻辑并不复杂。自己写代码更清楚,他人提交PR时更容易看懂。降低学习曲线。
好处
可以更轻松支持分页这种更复杂的UI逻辑 https://github.com/cloudreve/frontend/issues/12
感谢建议! 可能要到3.1版本那边的计划实现的差不多后才有时间开始进行重构。
我下周有空可以写单元测试
@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
。
- Duck模式可以的。
- 新代码写成TS也可以
- 重构State目前不太现实,改动太大了只能一点点改。
Why not consider importing Redux Toolkit?