使用 dva

在 umi@3 中要使用 dva 的功能很简单,只要使用安装 @umijs/plugin-dva 并在 配置文件中开启 dva 配置。

  1. yarn add @umijs/plugin-dva

如果提示 dva 不是约定的配置,说明你没有装 @umijs/plugin-dva ,如果你 dva 没有生效,可能是你配置没开启

教程在前面使用 create-umi-app 初始化项目时,依赖了 @umijs/preset-react ,这是一个插件集,你无需再而外安装 plugin-dva ,只需要再配置中开启即可。打开 umi 的配置文件:

./umirc.js

  1. import { defineConfig } from 'umi';
  2. export default defineConfig({
  3. dva: {},
  4. antd: {}
  5. });

新增 model 文件

umi 中启用 dva 时,约定 ./src/models/ 目录下的 model 文件将被视为 model 模块 ,可以在页面中使用。

这里的 model 模块不仅仅是指 dva model 还有可能是 useModel 的模块。umi会自己判断,这里我们先新建dva的模块就好。

新建 ./src/models/hero.ts

  1. import { Effect, Reducer } from 'umi';
  2. export interface HeroModelState {
  3. name: string;
  4. }
  5. export interface HeroModelType {
  6. namespace: 'hero';
  7. state: HeroModelState;
  8. effects: {
  9. query: Effect;
  10. };
  11. reducers: {
  12. save: Reducer<HeroModelState>;
  13. };
  14. }
  15. const HeroModel: HeroModelType = {
  16. namespace: 'hero',
  17. state: {
  18. name: 'hero',
  19. },
  20. effects: {
  21. *query({ payload }, { call, put }) {
  22. },
  23. },
  24. reducers: {
  25. save(state, action) {
  26. return {
  27. ...state,
  28. ...action.payload,
  29. };
  30. },
  31. },
  32. };
  33. export default HeroModel;

关于这个文件的详细说明,可以查看导读的《五分钟掌握最小知识体系》。这里需要说明的是,如果文件中的 namespace 未写明,umi 会使用文件名作为 model 的 namespace。为了减少错误的出现,最好保持所有的 model 文件,文件名不同。


在页面中使用model

在这里我们需要引入 dva 的 connect 将页面和 model 绑定在一起,我们稍微改造一下页面的结构:

./src/pages/hero.tsx

  1. import React, { FC } from 'react';
  2. import styles from './hero.css';
  3. import { connect, HeroModelState, ConnectProps } from 'umi'; ---step1
  4. interface PageProps extends ConnectProps {
  5. hero: HeroModelState;
  6. }
  7. const Hero: FC<PageProps> = (props) => { ---step2
  8. console.log(props.hero); ---step4
  9. return (
  10. <div>
  11. <h1 className={styles.title}>Page hero</h1>
  12. <h2>This is {props.hero.name}</h2>
  13. </div>
  14. );
  15. }
  16. export default connect(({ hero }: { hero: HeroModelState }) => ({ hero }))(Hero);
  17. --- step3
  • step1 在文件头部引入了 umi 的connect,HeroModelState, ConnectProps
  • step2 把之前的匿名函数,改成实名函数Hero
  • step3 使用connect连接页面和models
  • step4 从属性中取出namespace为hero的model的state数据。

这里有一点点绕口,比如我们现在定义的是

如果定义的是一个对象

  1. > state: 'hero',
  2. > console.log(props.hero);
  3. hero
  1. state: {
  2. text: 'page work',
  3. list: []
  4. },
  5. console.log(props.hero);
  6. {
  7. text: 'page work',
  8. list: []
  9. }

编辑完保存,启动 umi 开发服务器:

增加dva modules - 图1

使用同样的方法新建 ./src/models/item.js./src/models/summoner.js ,并同步修改 ./src/pages/item.js./src/pages/summoner.js


最终效果

增加dva modules - 图2

目录结构

  1. .
  2. ├── layouts
  3. ├── index.less
  4. └── index.tsx
  5. ├── models
  6. ├── hero.ts
  7. ├── item.ts
  8. └── summoner.ts
  9. └── pages
  10. ├── hero.less
  11. ├── hero.tsx
  12. ├── index.less
  13. ├── index.tsx
  14. ├── item.less
  15. ├── item.tsx
  16. ├── summoner.less
  17. └── summoner.tsx