美文网首页react + dva + antd
combineModels:合并多个dva的model

combineModels:合并多个dva的model

作者: luania | 来源:发表于2019-08-22 11:00 被阅读0次

    先放 combineModels 实现:

    实现比较简单:

    const combineModels = (...models) =>
      models.reduce((sum, item) => ({
        ...sum,
        ...item,
        state: {
          ...sum.state,
          ...item.state
        },
        reducers: {
          ...sum.reducers,
          ...item.reducers
        },
        effects: {
          ...sum.effects,
          ...item.effects
        },
        subscriptions: {
          ...sum.subscriptions,
          ...item.subscriptions
        }
      }), {} );
    

    意图:创建一个函数 combineModels,可以合并多个 model。也便于拆分比较庞大的 model

    比如现在有两个 model(没有指定 namespace):

    const modelLoading = {
      state: {
        loading: false
      },
      reducers: {
        loadingChange: (state, { loading }) => ({
          ...state,
          loading
        })
      }
    };
    const modelSubmitting = {
      state: {
        submitting: false
      },
      reducers: {
        submittingChange: (state, { submitting }) => ({
          ...state,
          submitting
        })
      }
    };
    

    将 modelLoading 与 modelSubmitting 合并

    const totalModel = combineModels(
      modelLoading,
      modelSubmitting,
      { namespace: "foo" } // 指定一下namespace
    );
    

    那么得到一个合并后的 totalModel 对象, 维护了 loading 和 submitting 两个状态, totalModel 如下:

    {
      namespace: "foo",
      state: {
        loading: false,
        submitting: false
      },
      reducers: {
        loadingChange: (state, { loading }) => ({
          ...state,
          loading
        }),
        submittingChange: (state, { submitting }) => ({
          ...state,
          submitting
        })
      }
    };
    

    拆分大型 model

    一般做项目的时候一个 page 对应一个 model,管理的状态会比较多而杂乱

    这时候可以将大型的 Model(比如 totalModel)分解成小型的 model(modelLoading,modelSubmitting)

    对相似的小型 model 再进行重构

    创建管理单一变量的 model

    const createSingleStateModel = (name, initValue) => ({
      state: {
        [name]: initValue
      },
      reducers: {
        [`${name}Change`]: (state, action) => ({
          ...state,
          [name]: action[name]
        })
      }
    });
    const modelLoading = createSingleStateModel('loading', false);
    const modelSubmitting = createSingleStateModel('submitting', false);
    const modelCount = createSingleStateModel('count', 0);
    

    一个比较实际的案例

    原来的 model

    const apiLoadData = () =>
      new Promise(r =>
        r({
          data: []
        })
      );
    const apiSubmit = () => new Promise(r => r({}));
    const fooModel = {
      namespace: "foo",
    
      state: {
        loading: false,
        data: [],
        submitting: false
      },
    
      effects: {
        *loadData(action, { call, put }) {
          yield put({ type: "loadingOn" });
          try {
            const data = yield call(apiLoadData);
            yield put({
              type: "dataChange",
              data
            });
          } catch (e) {
          } finally {
            yield put({ type: "loadingOff" });
          }
        },
        *submit(action, { call, put }) {
          yield put({ type: "submittingOn" });
          try {
            const data = yield call(apiSubmit);
          } catch (e) {
          } finally {
            yield put({ type: "submittingOff" });
          }
        }
      },
    
      reducers: {
        loadingOn: (state, action) => ({
          ...state,
          loading: true
        }),
        loadingOff: (state, action) => ({
          ...state,
          loading: false
        }),
        submittingOn: (state, action) => ({
          ...state,
          submitting: true
        }),
        submittingOff: (state, action) => ({
          ...state,
          submitting: false
        }),
        dataChange: (state, { data }) => ({
          ...state,
          data
        })
      }
    };
    

    提取 createDoingModel

    const createDoingModel = (name) => ({
      state: {
        [name]: false
      },
      reducers: {
        [`${name}On`]: (state, action) => ({
          ...state,
          [name]: true
        }),
        [`${name}Off`]: (state, action) => ({
          ...state,
          [name]: false
        })
      }
    });
    

    结合 createSingleStateModel, 那么 fooModal 就变成了

    const fooModel = combineModels(
      createDoingModel("loading"),
      createDoingModel("submitting"),
      createSingleStateModel("data", []),
      {
        namespace: "foo",
    
        effects: {
          *loadData(action, { call, put }) {
            yield put({ type: "loadingOn" });
            try {
              const data = yield call(apiLoadData);
              yield put({
                type: "dataChange",
                data
              });
            } catch (e) {
            } finally {
              yield put({ type: "loadingOff" });
            }
          },
          *submit(action, { call, put }) {
            yield put({ type: "submittingOn" });
            try {
              const data = yield call(apiSubmit);
            } catch (e) {
            } finally {
              yield put({ type: "submittingOff" });
            }
          }
        }
      }
    );
    

    把数据加载和提交逻辑分开

    const loadDataModel = combineModels(
      createDoingModel("loading"),
      createSingleStateModel("data", []),
      {
        effects: {
          *loadData(action, { call, put }) {
            yield put({ type: "loadingOn" });
            try {
              const data = yield call(apiLoadData);
              yield put({
                type: "dataChange",
                data
              });
            } catch (e) {
            } finally {
              yield put({ type: "loadingOff" });
            }
          }
        }
      }
    );
    const submitModel = combineModels(
      createDoingModel("submitting"),
      {
        effects: {
          *submit(action, { call, put }) {
            yield put({ type: "submittingOn" });
            try {
              const data = yield call(apiSubmit);
            } catch (e) {
            } finally {
              yield put({ type: "submittingOff" });
            }
          }
        }
      }
    );
    const fooModel = combineModels(
      loadDataModel,
      submitModel,
      { namespace: "foo" }
    );
    

    相关文章

      网友评论

        本文标题:combineModels:合并多个dva的model

        本文链接:https://www.haomeiwen.com/subject/mhngsctx.html