Redux --瘦身之路

前言

公司中臺項目使用 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);
相關文章
相關標籤/搜索