Skip to content

v3.9.3

Choose a tag to compare

@Ahoo-Wang Ahoo-Wang released this 27 Dec 03:38
· 70 commits to main since this release

What's Changed

🎉 New Features

  • feat(react): add createExecuteApiHooks utility for generating API method hooks by @Ahoo-Wang in #985
  • feat(api): add appendAbortController option to API hooks by @Ahoo-Wang in #986

createExecuteApiHooks

🚀 自动类型安全 API Hooks 生成 - 从 API 对象自动生成完全类型化的 React hooks,具有自动方法发现、类方法支持和高级执行控制。

createExecuteApiHooks 函数自动发现 API 对象中的所有函数方法(包括类实例的原型链),并使用命名模式 use{首字母大写的方法名} 创建相应的 React hooks。每个生成的 hook 都提供完整的状态管理、错误处理,并支持具有类型安全参数访问的自定义执行回调。

主要特性:

  • 自动方法发现:遍历对象属性和原型链
  • 类型安全 Hook 生成:参数和返回类型的完整 TypeScript 推断
  • 类方法支持:处理静态方法和具有 this 绑定的类实例
  • 执行控制onBeforeExecute 回调用于参数检查/修改和中止控制器访问
  • 自定义错误类型:支持指定超出默认 FetcherError 的错误类型
import { createExecuteApiHooks } from '@ahoo-wang/fetcher-react';
import { api, get, post, patch, path, body, autoGeneratedError } from '@ahoo-wang/fetcher-decorator';

// 使用装饰器定义您的 API 服务
import { api, get, post, patch, path, body, autoGeneratedError } from '@ahoo-wang/fetcher-decorator';

@api('/users')
class UserApi {
  @get('/{id}')
  getUser(@path('id') id: string): Promise<User> {
    throw autoGeneratedError(id);
  }

  @post('')
  createUser(@body() data: { name: string; email: string }): Promise<User> {
    throw autoGeneratedError(data);
  }

  @patch('/{id}')
  updateUser(@path('id') id: string, @body() updates: Partial<User>): Promise<User> {
    throw autoGeneratedError(id, updates);
  }
}

const userApi = new UserApi();

// 生成类型安全的 hooks
const apiHooks = createExecuteApiHooks({ api: userApi });

function UserComponent() {
  // Hooks 自动生成,具有正确的类型
  const { loading: getLoading, result: user, error: getError, execute: getUser } = apiHooks.useGetUser();
  const { loading: createLoading, result: createdUser, error: createError, execute: createUser } = apiHooks.useCreateUser({
    onBeforeExecute: (abortController, args) => {
      // args 完全类型化为 [data: { name: string; email: string }]
      const [data] = args;
      // 如果需要,可以就地修改参数
      data.email = data.email.toLowerCase();
      // 访问中止控制器以进行自定义取消
      abortController.signal.addEventListener('abort', () => {
        console.log('用户创建已取消');
      });
    },
  });

  const handleFetchUser = (userId: string) => {
    getUser(userId); // 完全类型化 - 仅接受字符串参数
  };

  const handleCreateUser = (userData: { name: string; email: string }) => {
    createUser(userData); // 完全类型化 - 仅接受正确的数据形状
  };

  return (
    <div>
      <button onClick={() => handleFetchUser('123')}>
        获取用户
      </button>
      {getLoading && <div>正在加载用户...</div>}
      {getError && <div>错误: {getError.message}</div>}
      {user && <div>用户: {user.name}</div>}

      <button onClick={() => handleCreateUser({ name: 'John', email: 'john@example.com' })}>
        创建用户
      </button>
      {createLoading && <div>正在创建用户...</div>}
      {createError && <div>错误: {createError.message}</div>}
      {createdUser && <div>已创建: {createdUser.name}</div>}
    </div>
  );
}

Full Changelog: v3.9.2...v3.9.3