公司中臺項目使用 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);