umi项目使用dva(简单上手)

1,563 阅读2分钟

记录ant design pro(umi搭建)项目中使用dva

1.启用

umi内置dva,其内部包依赖dva,就会默认下载@umijs/plugin-dva.

dva 通过 model 的概念把一个领域的模型管理起来,包含同步更新 state 的 reducers,处理异步逻辑的 effects,订阅数据源的 subscriptions

2.按规则创建models,其内部文件才会被应用起来

  • src/models 下的文件
  • src/pages 下,子目录中 models 目录下的文件
  • src/pages 下,所有 model.ts 文件(不区分任何字母大小写)

models文件夹下的文件如果不指定namespace,文件名即 namespace

3.配置dva

export default {
  dva: {
    immer: true, // 启用immer以方便修改reducer
    hmr: false, // 热更新
  },
};

4.页面使用

import { connect } from 'umi';

const Index: React.FC = ({ card, dispatch }: any) => {
  // 通过namespace取state
  const { option } = card;
  
  useEffect(() => {
    // 派发action进行切割
    dispatch({
      type: 'card/addSplit', // 因为有多个namespace
      payload: [
        {
          start: 0,
          end: 0,
        },
      ],
    });
  });
  
  useEffect(() => {
    // 派发action进行初始化
    dispatch({ type: 'card/init' });
  }, []);


  return (
    <>
      <div>{JSON.stringify(option)}</div>
    </>
  );
};

// 将state应用到DOM上
export default connect((states: any) => ({
  ...states,
}))(Index);

5.model用例

image.png

import { Effect, ImmerReducer, Reducer, Subscription } from 'umi';

export interface IndexModelState {
  name: string;
}

export interface IndexModelType {
  namespace: 'card'; 
  state: IndexModelState;
  effects: {
    query: Effect;
  };
  reducers: {
    save: Reducer<IndexModelState>;
    // save: ImmerReducer<IndexModelState>;
  };
  subscriptions: { setup: Subscription };
}

// 异步请求接口
const request = () => {
  return new Promise<any>(async (resolve, reject) => {
    // resolve(await cardInit());
  });
};

const IndexModel: IndexModelType = {
  namespace: 'card', // 派发action时,格式: card/xxx
  // 默认state
  state: {
    name: '',
  },
  // 同步操作state
  reducers: {
    save(state, action) {
      return {
        ...state,
        ...action.payload,
      };
    },
    // 启用 immer 之后
    // save(state, action) {
    //   state.name = action.payload;
    // },
  },
  // 异步操作state
  effects: {
    // *和yield就相当于async/await的底层实现
    *query({ payload }, { call, put, select }: any) {
      // put可以进行dispatch(触发action)   
      // call用来请求接口(支持promise)   
      // select获取所有的state
      yield put({ type: 'save', payload: {} }); // type不需要加namespace
      let res = yield call(requset);
      // 加一些处理逻辑
      let states = yield select();
    },
  },
  subscriptions: {
    // 进入/users页面,触发action`users/fetch`
    setup({ dispatch, history }) {
      history.listen(({ pathname }) => {
        if (pathname === '/users') {
          dispatch({
            type: 'users/fetch',
          });
        }
      });
    },
  },
};

export default IndexModel;

注意: reducers和effects的函数名不能重复

image.png

大致理解: 使用connect将view与store进行连接之后,可以获取每个namespace下的state进行使用.

需要同步操作state时,使用dispatch({type: 'namespace/xxx', payload: xxx}).

异步操作也使用dispatch({type: 'namespace/xxx', payload: xxx}),内部修改state时,要进行同步操作.也就是执行put({type: 'namespace/xxx', payload: xxx})