Model 插件

@umijs/plugin-model 是 Umi 内置的一种轻量级、基于 Hooks 的数据流方案。它旨在解决组件间状态共享的问题,同时避免 Redux 等方案中繁琐的 Boilerplate 代码。


📋 目录


核心理念

Umi Model 插件的核心理念是:“一个文件就是一个 Hook”

1. 本质公式

Umi Model = 自定义 Hook + 全局共享 (单例模式)

2. 直观比喻

  • 普通自定义 Hook 是一面 “随身镜”:每个组件调用时都会给自己生成一个独立的状态。
  • Umi Model 是挂在店中央的一块 “大屏幕”:应用中任何地方看到的都是同一块屏幕。

开始使用:命名空间规则

所谓的 Model,就是一个默认导出的自定义 Hook。Umi 会根据文件路径自动生成 命名空间(Namespace)

1. 命名空间生成表

路径命名空间说明
src/models/count.tscountsrc/models 目录下不支持嵌套定义
src/pages/pageA/model.tspageA.model页面级 model
src/pages/pageB/models/product.tspageB.product页面级 models 目录
src/pages/pageB/models/fruit/apple.tspageB.fruit.applepages 目录下支持嵌套定义

2. 编写 Model 示例

// src/models/userModel.ts
import { useState } from 'react';
 
export default () => {
  const [user, setUser] = useState({ username: 'umi' });
  return { user, setUser };
};

全局初始状态 @@initialState

@@initialState 是一种特殊的、内置的全局 Model。它在项目启动的最开始创建,通常用于存储当前用户、权限、全局配置等。

1. 初始化 (src/app.ts)

// src/app.ts
export async function getInitialState() {
  const data = await fetchUserInfo();
  return data; // 这里的返回值就是 initialState
}

2. 消费状态

const { initialState, loading, refresh, setInitialState } = useModel('@@initialState');

使用 Model

在组件中通过 useModel(namespace) 获取状态。

import { useModel } from 'umi';
 
export default () => {
  const { user } = useModel('userModel');
  const { initialState } = useModel('@@initialState');
  return <div>{user.username}</div>;
};

性能优化:选择器

useModel 的第二个参数是可选的 updater (Selector)。当 Model 中只有部分参数变化时,使用它可以避免不必要的重渲染。

// 只有当 count 变化时,该组件才会重新渲染
const { count } = useModel('counterModel', (model) => ({
  count: model.count,
}));

💡 核心进阶:页面内“小模块” Modal vs 全局 Modal

1. 场景决策指南

维度页面/组件内“小模块” Modal全局/应用级 Model Modal
存放位置页面组件内部(使用 useStatesrc/models/ 目录
状态归属私有状态:只为当前页面服务共享状态:跨页面或全局组件(如导航栏)
小白建议90% 的业务弹窗请选这个。5% 的全局弹窗(如登录、公告)选这个。

2. 代码实战与目录管理

A. 局部 Modal(推荐)

目录结构:

src/pages/User/
  ├── index.tsx          # 状态定义在这里 (useState)
  └── components/
      └── EditModal.tsx  # 纯展示/接收 Props 的 Modal

B. 全局 Modal(跨组件联动)

目录结构:

src/
  ├── models/
  │   └── useAuthModel.ts  # 定义全局控制逻辑
  ├── components/
  │   └── LoginModal.tsx   # 登录弹窗
  └── layouts/
      └── index.tsx        # 在这里挂载 LoginModal,实现全站调用

🚀 进阶:微前端通信 (@@qiankunStateFromMaster)

当作为微前端子应用运行时,Umi 内置了该 Model 用于接收主应用下发的数据。

const masterState = useModel('@@qiankunStateFromMaster');

最佳实践

  1. 命名规范:建议以 useXXXModel.ts 命名,目录必选复数 src/models
  2. 状态下沉:不要把所有状态都塞进全局,优先考虑组件内 useState
  3. 性能意识:大 Model 务必使用 Selector 优化。
  4. 配合 useRequest:将异步数据请求结果存入 Model 是 Umi 开发的标准模式。

🔗 相关链接


最后更新:2026-01-14 维护规范:遵循 .cursorrules

Umi Model插件 数据流 initialState 状态管理