safety-eval-service-frontend/.cursor/skills/specs/11-接口与数据层规范/03-命名空间与视图连接/SKILL.md

7.3 KiB
Raw Blame History

name description
jjb-connect 定义 JJB 命名空间与视图连接规范。在使用 Connect 装饰器、defineNamespace、injectActionProps 或 resetModelState 时使用。

接口与数据层规范

命名空间与视图连接

Connect@cqsjjb/jjb-dva-runtime 提供的高阶组件HOC用于将 Dva 模型Model与 React 组件连接。它支持自动注入模型 state、工具方法以及可选的请求 Action简化了组件与数据层的交互。

命名空间定义规范

  • 集中定义:命名空间必须集中在 src/enumerate/namespace/index.js 中定义

  • 定义方式:使用 defineNamespace 函数定义命名空间常量

  • 命名规则:命名空间常量对应 src/api/<namespace>/index.js 文件

// 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/<namespace>/index.js 文件

  • 声明方式:使用 declareRequest 声明接口请求(具体用法参考 02-接口定义规范

// 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 字段判断接口是否成功:

      this.props.xxxAction().then(res => {
        // 必须通过 success 判断这个接口是否成功
        if (res.success) {
          // 接口成功后的处理逻辑
        }
      });
      
    • 注意如果接口失败了不需要手动抛出接口异常错误http 内部模块已自动拦截并提示错误

使用方式

方式一默认模式injectActionProps = false - 不推荐

说明:以下示例仅用于对比理解两种方式的区别,实际开发中请使用推荐的方式二。

此时不会自动注入 Action需要手动调用 dispatchModelAction

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 <div>{user.userInfo?.name}</div>;
}

// 注意这里第二个参数没有传(默认为 false
export default Connect([NS_USER])(UserProfile);

方式二:自动注入 ActioninjectActionProps = true - 推荐

injectActionProps = true 时,模型中通过 declareRequest 声明的请求会自动注入到组件 props 中,使用时无需 dispatchModelAction,可以直接调用:

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 <div>{user.userInfo?.name}</div>;
}

// 第二个参数传 true启用 Action 自动注入到 props
export default Connect([NS_USER], true)(UserProfile);

类组件装饰器语法

如果要连接 class 类组件,使用装饰器语法:

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 <div>{user.userInfo?.name}</div>;
  }
}

export default UserProfile;

多个模型连接示例

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 (
    <div>
      <h3>{user?.userInfo?.name}</h3>
      <ul>
        {order.list?.map(o => (
          <li key={o.id}>{o.title}</li>
        ))}
      </ul>
    </div>
  );
}

export default Connect([NS_USER, NS_ORDER], true)(Dashboard);

重置状态示例

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 <div>{user.userInfo?.name}</div>;
}

export default Connect([NS_USER], true)(UserProfile);

使用规范总结

  1. 命名空间必须集中在 src/enumerate/namespace/index.js 中定义,使用 defineNamespace 函数

  2. 请求声明必须放在 src/api/<namespace>/index.js 中,使用 declareRequest

  3. Connect 负责把 state、action 方法注入到组件

  4. 如果 injectActionProps = truestate、action 自动注入到组件 props免去手动处理

  5. 禁止行为:禁止在页面内使用 useState 管理本应由 declareRequest 处理的接口数据或 Loading 状态