公司中台项目使用 redux 进行状态管理,众所周知,redux 写起来就是在浪费生命。但鉴于项目重构成本太大,所以决定先在不改变框架的状况下,在原先代码的基础上一步步优化简化 redux 用法。redux
先来看看原来的文件目录结构:promise
├── store │ └── modules │ ├── todoList │ │ ├── todoList_action.js │ │ ├── todoList_reducer.js │ │ ├── todoList_state.js │ │ └── todoList_types.js
页面代码:框架
// todoList_types.js export const types = { TODO_LIST: "TODO_LIST", };
// todoList_action.js import types from "./todoList_types"; // 接口 import { todoListSvr } from "services/card"; // 使用了 thunkMiddleware 中间件 export const todoList = (params) => ({ type: types.TODO_LIST, payload: { // 使用了 promiseMiddleware 中间件 promise: todoListSvr(params), }, });
// todoList_reducer.js import types from "./todoList_types"; import initialState from "./todoList_state"; // 工具函数,用于简化 reducer 代码 export const createReducer = (initialparams, reducerMap) => ( params = initialparams, action ) => { const reducer = reducerMap[action.type]; return reducer ? reducer(params, action.payload ? action.payload : {}, action.params) : params; }; export default createReducer(initialState, { [`${types.TODO_LIST}_PENDING`]: (state) => { return Object.assign({}, state, { todoListLoading: true }); }, [`${types.TODO_LIST}_ERROR`]: (state) => { return Object.assign({}, state, { todoListLoading: false }); }, [`${types.TODO_LIST}_SUCCESS`]: (state, data) => { return Object.assign({}, state, { todoList: data, todoListLoading: false }); }, });
// todoList_state.js export default { todoListLoading: false, todoList: [], };
能够看到,每写一个页面(功能)都要在 4 个文件里来回跳转。因此首先,最容易想到的就是合并文件,把 action、reducer、type、state 都放在一个文件中处理。这样能够解决来回跳转的问题。函数
而后再观察一下代码,能够发现沉余的就是 reducer 代码。而这里面主要就是 loading 状态的处理。
参考了许多文章,最终优化代码以下:工具
// todo.js // 接口 import { todoListSvr } from "services/card"; // types export const types = { TODO_LIST: "TODO_LIST", }; // actions方法 export const actions = { todoList: (obj) => ({ type: types.TODO_LIST, payload: { // 使用了 promiseMiddleware 中间件 promise: todoListSvr(params), }, }), }; // state数据 const initialState = { todoList: [], }; // reducer export default createReducer(initialState, { [`${types.TODO_LIST}_SUCCESS`]: (state, data) => Object.assign({}, state, { todoList: data }), });
// loadingReducer.js const loadingReducer = (state = {}, action) => { const { type } = action; const matches = /(.*)_(PENDING|SUCCESS|ERROR)/.exec(type); if (!matches) return state; const [, requestName, requestState] = matches; return { ...state, [requestName]: requestState === "PENDING", }; }; // 页面内使用:const mapStateToProps = (state) => ({ isLoading: loadingSelector(['TODO_LIST'])(state) }) export const loadingSelector = (actions) => (state) => actions.some((action) => state.loadingReducer[action]); export default loadingReducer;
页面内使用:优化
import { loadingSelector } from "store/modules/loadingReducer"; const mapStateToProps = (state) => ({ isLoading: loadingSelector(["TODO_LIST"])(state), }); export default connect(mapStateToProps)(Todo);