--- name: jjb-connect description: 定义 JJB 命名空间与视图连接规范。在使用 Connect 装饰器、defineNamespace、injectActionProps 或 resetModelState 时使用。 --- # 接口与数据层规范 ## 命名空间与视图连接 `Connect` 是 `@cqsjjb/jjb-dva-runtime` 提供的高阶组件(HOC),用于将 Dva 模型(Model)与 React 组件连接。它支持自动注入模型 state、工具方法,以及(可选的)请求 Action,简化了组件与数据层的交互。 ## 命名空间定义规范 - **集中定义**:命名空间必须集中在 `src/enumerate/namespace/index.js` 中定义 - **定义方式**:使用 `defineNamespace` 函数定义命名空间常量 - **命名规则**:命名空间常量对应 `src/api//index.js` 文件 ```javascript // src/enumerate/namespace/index.js import { defineNamespace } from '@cqsjjb/jjb-dva-runtime'; // 这里 user 指的是 src/api/user/index.js export const NS_USER = defineNamespace('user'); // 这里 order 指的是 src/api/order/index.js export const NS_ORDER = defineNamespace('order'); // 这里 examList 指的是 src/api/examList/index.js export const NS_EXAM_LIST = defineNamespace('examList'); ``` ## 请求声明规范 - **文件位置**:每个命名空间常量对应一个 `src/api//index.js` 文件 - **声明方式**:使用 `declareRequest` 声明接口请求(具体用法参考 [`02-接口定义规范`](../02-接口定义规范/SKILL.md)) ```javascript // src/api/user/index.js import { declareRequest } from '@cqsjjb/jjb-dva-runtime'; // 获取用户信息 export const fetchUserAction = declareRequest( 'loading', 'Get > /api/user/{id}', 'userInfo: {} | res.data || {}' ); // 新增用户(使用 @ 标记) export const addUserAction = declareRequest( 'confirmLoading', 'Post > @/api/user' ); ``` ## Connect API 说明 - **函数签名**:`Connect(models, injectActionProps?)` - **参数说明**: | 参数 | 类型 | 必填 | 说明 | | :--- | :--- | :--- | :--- | | models | Namespace[] | 是 | 命名空间数组,必须从 `src/enumerate/namespace` 引入 | | injectActionProps | boolean | 否 | 是否自动注入 action 方法,默认为 `false` | - **injectActionProps 参数说明**: - `false`(默认):只能使用 `dispatchModelAction(namespace, effectAction, payload)` 手动调用 - `true`:所有 `declareRequest` 定义的请求会自动注入到组件 props 中,可直接调用 ## 注入的 Props 1. **State 注入**: - `props.user` → 对应 `NS_USER` 模型 - `props.order` → 对应 `NS_ORDER` 模型 - 每个命名空间对应一个 props 属性,包含该模型的所有 state(数据字段和 Loading 状态) 2. **工具方法**(始终存在): - `models`:所有连接的模型 - `getModelState(namespace, name)`:获取模型状态 - `resetModelState(namespace, state)`:重置模型状态 - `dispatchModelAction(namespace, effectAction, payload?)`:手动调用 Action - `dispatch(type, payload?)`:Dva dispatch 方法 3. **Action 方法**(当 `injectActionProps = true` 时才存在): - 例如 `declareRequest` 定义的 `fetchUserAction` 会在组件 props 中直接可用 - Action 方法返回 Promise,使用时需要通过 `success` 字段判断接口是否成功: ```javascript this.props.xxxAction().then(res => { // 必须通过 success 判断这个接口是否成功 if (res.success) { // 接口成功后的处理逻辑 } }); ``` - **注意**:如果接口失败了,不需要手动抛出接口异常错误,http 内部模块已自动拦截并提示错误 ## 使用方式 ### 方式一:默认模式(injectActionProps = false) - 不推荐 > **说明**:以下示例仅用于对比理解两种方式的区别,实际开发中请使用推荐的方式二。 此时不会自动注入 Action,需要手动调用 `dispatchModelAction`: ```javascript import React, { useEffect } from 'react'; import { Connect } from '@cqsjjb/jjb-dva-runtime'; import { NS_USER } from '~/enumerate/namespace'; function UserProfile({ user, dispatchModelAction }) { useEffect(() => { dispatchModelAction(NS_USER, 'fetchUserAction', { id: 1 }); }, []); console.log(user?.loading); console.log(user?.confirmLoading); return
{user.userInfo?.name}
; } // 注意这里第二个参数没有传(默认为 false) export default Connect([NS_USER])(UserProfile); ``` ### 方式二:自动注入 Action(injectActionProps = true) - 推荐 当 `injectActionProps = true` 时,模型中通过 `declareRequest` 声明的请求会自动注入到组件 props 中,使用时无需 `dispatchModelAction`,可以直接调用: ```javascript import React, { useEffect } from 'react'; import { Connect } from '@cqsjjb/jjb-dva-runtime'; import { NS_USER } from '~/enumerate/namespace'; function UserProfile({ user, fetchUserAction }) { useEffect(() => { fetchUserAction({ id: 1 }); }, []); console.log(user?.loading); console.log(user?.confirmLoading); return
{user.userInfo?.name}
; } // 第二个参数传 true,启用 Action 自动注入到 props export default Connect([NS_USER], true)(UserProfile); ``` ### 类组件装饰器语法 如果要连接 class 类组件,使用装饰器语法: ```javascript import React, { Component } from 'react'; import { Connect } from '@cqsjjb/jjb-dva-runtime'; import { NS_USER } from '~/enumerate/namespace'; @Connect([NS_USER], true) class UserProfile extends Component { componentDidMount() { this.props.fetchUserAction({ id: 1 }); } render() { const { user } = this.props; return
{user.userInfo?.name}
; } } export default UserProfile; ``` ### 多个模型连接示例 ```javascript import React, { useEffect } from 'react'; import { Connect } from '@cqsjjb/jjb-dva-runtime'; import { NS_USER, NS_ORDER } from '~/enumerate/namespace'; function Dashboard({ user, order, fetchUserAction, fetchOrdersAction }) { useEffect(() => { fetchUserAction({ id: 1 }); fetchOrdersAction(); }, []); return (

{user?.userInfo?.name}

    {order.list?.map(o => (
  • {o.title}
  • ))}
); } export default Connect([NS_USER, NS_ORDER], true)(Dashboard); ``` ### 重置状态示例 ```javascript import { useEffect } from 'react'; import { Connect } from '@cqsjjb/jjb-dva-runtime'; import { NS_USER } from '~/enumerate/namespace'; function UserProfile({ user, fetchUserAction, resetModelState }) { useEffect(() => { fetchUserAction({ id: 1 }); return () => { // 组件销毁时重置状态 resetModelState(NS_USER, { loading: false, userInfo: {} }); }; }, []); return
{user.userInfo?.name}
; } export default Connect([NS_USER], true)(UserProfile); ``` ## 使用规范总结 1. 命名空间必须集中在 `src/enumerate/namespace/index.js` 中定义,使用 `defineNamespace` 函数 2. 请求声明必须放在 `src/api//index.js` 中,使用 `declareRequest` 3. `Connect` 负责把 state、action 方法注入到组件 4. 如果 `injectActionProps = true`,state、action 自动注入到组件 props,免去手动处理 5. **禁止行为**:禁止在页面内使用 `useState` 管理本应由 `declareRequest` 处理的接口数据或 Loading 状态