, ,

Umi + Dva 内置自动生成的插件状态(dva-loading)

底层原理(插件自动劫持 effect) 插件利用 dva 的 onEffect 钩子: 二、loading 对…

  1. 只要你在 .umirc.ts 开启了 dva: {},Umi 会自动内置 dva-loading 插件,不需要手动新建 loading.js model
  2. 插件内部自动注入一套 reducer、监听所有 effects 异步函数,自动维护全局 loading 数据;
  3. 全局根 state 顶层直接多出一个 loading 对象,所以可以直接写 state => state.loading

底层原理(插件自动劫持 effect)

插件利用 dva 的 onEffect 钩子:

  1. 任意 yield call() 发起接口请求前 → 自动 dispatch action,标记 loading = true;
  2. 接口请求成功 / 失败结束后 → 自动 dispatch action,标记 loading = false; 全程不用你手动写 setLoading(true/false)

二、loading 对象完整结构(打印看得到)

loading = {
  global: false,          // 全局:任意接口在请求就为 true
  models: {
    user: false,          // user 模块任意effect请求中=true
    goods: false
  },
  effects: {
    'user/fetchInfo': false, // 精准单个接口 loading
    'goods/getList': false
  }
}

三、每个字段作用 & 业务使用场景

1. loading.global(全局转圈、全局遮罩)

只要项目里任意接口正在请求,值为 true

const loading = useSelector(state => state.loading);
// 全局loading遮罩
<Spin spinning={loading.global}>{页面内容}</Spin>

2. loading.models.xxx(按模块控制 loading)

xxx 是 model 的 namespace,该 model 下任意 effect 请求中 = true。

// user模型任意接口加载时,表格转圈
const userLoading = useSelector(state => state.loading.models.user);
<Table loading={userLoading} />

3. 精准单个接口 loading

loading.effects['namespace/effect名'](精准单个接口 loading)

只监听某一个具体接口,适合同一页面多个按钮分别 loading:

// 只监听 user/fetchList 这个effect
const tableLoading = useSelector(state => state.loading.effects['user/fetchList']);
const submitLoading = useSelector(state => state.loading.effects['user/save']);

<Table loading={tableLoading} />
<Button loading={submitLoading}>提交</Button>

  1. 全局统一加载动画、页面遮罩;
  2. 控制 Table、Modal、Form 的加载转圈;
  3. 防止重复点击提交按钮(loading 为 true 时禁用按钮);
  4. 骨架屏、加载提示文案统一管理。

完整组件示例:

import { useSelector, useDispatch } from 'dva';
import { Spin, Table, Button } from 'antd';

export default function UserPage() {
  const dispatch = useDispatch();
  // 获取整套loading状态
  const loading = useSelector(state => state.loading);
  // 精准取当前表格接口loading
  const tableLoading = loading.effects['user/fetchList'];

  const loadData = () => {
    dispatch({ type: 'user/fetchList' });
  };

  return (
    <Spin spinning={loading.global}>
      <Button onClick={loadData} loading={tableLoading}>
        刷新列表
      </Button>
      <Table loading={tableLoading} />
    </Spin>
  );
}

五、常见疑问

1. 为什么我项目里找不到 loading.js model?

因为是框架内置插件自动生成,不是手动创建的 src/models 文件,源码在 umi 内部插件里,项目目录看不到。

2. 关闭 dva 后 loading 就消失

.umirc.ts 如果删掉 dva:{immer:true},dva 插件失效,state.loading 会直接不存在,访问会报错。

3. 为什么不用自己维护 loading 变量?

传统 redux 需要每个 effect 手动写:

// 传统写法,冗余
yield put({type:'user/setLoading', payload:true})
yield call(request, '/api')
yield put({type:'user/setLoading', payload:false})

dva-loading 全自动处理,省去重复代码。

Previous Post

Next Post

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

About the Author

每个人都有自己得时区,在自己得时区里,一切都是准时的。

BlockSpare — News, Magazine and Blog Addons for (Gutenberg) Block Editor