Skip to content

React ​

React Hook 将异步操作连接到一个挂载组件:状态、执行、查询驱动刷新及可选防抖。它们不提供共享响应缓存。显式操作从执行 Hook 开始;只有输入改变应发送请求时才使用自动查询。

所有 Hook 遵循同一模型:请求以其 AbortController 标识,只有当前请求可以写入状态。状态是一个值 { status, loading, result, error };execute 从不拒绝,解析为执行结束时的状态。查询是受控的:查询保存在你的状态中,内容变化时 Hook 执行。

选择入口 ​

需求入口应用负责
点击发送 HTTPuseFetcherURL、Fetcher 和结果提取器;渲染 result,按 execute 解析出的状态分支。
执行其他 Promise APIuseExecutePromiseSupplier,并将其 controller signal 传给 I/O。
查询变化时请求useQuery / useFetcherQuery查询,保存在你自己的状态中;undefined 表示未就绪。默认自动执行。
输入时延迟搜索防抖 Hook必填延迟;防抖查询增加 pending 和 flush(),abort() 停止活动请求。
包装现有服务API Hook 工厂服务对象和方法;在渲染外创建 Hook 集合。
只记录其他系统的状态usePromiseState执行、清理和旧结果抑制由状态 Hook 外部负责。

子路径入口 ​

入口导出加载
@ahoo-wang/fetcher-react这些页面上的全部 Hook 与组件下方声明的全部 peer
@ahoo-wang/fetcher-react/corePromise 与查询状态、防抖回调/值/查询、useLatest、useStableValue只有 React,不加载任何 @ahoo-wang/* 包
@ahoo-wang/fetcher-react/fetcheruseFetcher、useFetcherQuery、useDebouncedFetcher、useDebouncedFetcherQuery 及其选项类型@ahoo-wang/fetcher;不加载 CoSec、存储或事件总线

子路径只提供 ESM;根入口另有 UMD 构建。子路径与根入口共用一个模块图,所以从 /core 导入的 Hook 或 PromiseStatus 与从根入口导入的是同一个值。符号索引标出每个符号由哪个子路径导出。导入子路径时,声明的 peer 仍是安装前提;子路径只限制打包加载的内容。

完整安装前提 ​

sh
pnpm add @ahoo-wang/fetcher @ahoo-wang/fetcher-cosec @ahoo-wang/fetcher-eventbus @ahoo-wang/fetcher-react @ahoo-wang/fetcher-storage react react-dom

库包声明 Node >=18.20.8;仓库开发要求 Node >=22.12.0、pnpm 10.34.5。命令包含全部递归内部 peer(React → CoSec → 存储 → 事件总线);直接运行依赖(dequal、immer)自动安装。外部 peer 为 React ^19.0.0;渲染器按应用需要安装(浏览器用 react-dom)。即使不使用某项功能,peer 仍是安装前提。消费者无需复制仓库的 React Compiler 工具链。

6.0 变更

这些 Hook 已按上述模型重构(破坏性变更)。移除了全屏 Hook、useRefs、useForceUpdate、useMounted、useRequestId、useQueryState、propagateError 选项、initialQuery/setQuery/getQuery 和 onBeforeExecute。各专题页说明其 Hook 的变化;最新值与稳定值列出被移除工具的替代方案。

Wow 查询 Hook 与数据监控

Wow 查询 Hook(useListQuery、usePagedQuery、useFetcherListQuery 等)与数据监控 Hook(useDataMonitor、DataMonitorService)只保留在 5.x 线(npm 5.1.x,分支 5.x)。从 6.0 起,Wow Hook 位于 Wow 仓库的 @ahoo-wang/wow-react(typescript/,文档);它自 Wow 9.2.0 起已发布到 npm,9.2.1 及以上兼容 fetcher 6。数据监控 Hook 随 @ahoo-wang/fetcher-viewer 一同退役。

可运行核心示例 ​

运行步骤、服务夹具与预期结果见接入指南.

tsx
/*
 * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *      http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { Fetcher, ResultExtractors } from '@ahoo-wang/fetcher';
import { useFetcher } from '@ahoo-wang/fetcher-react';
import { useMemo } from 'react';

interface User {
  id: string;
  name: string;
}

type Result = User[] | { status: string };

export function ReactRequests({ baseURL = '/api' }: { baseURL?: string }) {
  const fetcher = useMemo(() => new Fetcher({ baseURL }), [baseURL]);
  const request = useFetcher<Result>({
    fetcher,
    resultExtractor: ResultExtractors.Json,
  });

  const output = request.loading
    ? request.status
    : request.error
      ? `Error · ${request.error.name}`
      : Array.isArray(request.result)
        ? request.result.map(user => user.name).join(', ')
        : (request.result?.status ?? request.status);

  return (
    <section
      aria-label="React requests"
      style={{ display: 'grid', gap: '0.75rem', maxWidth: '24rem' }}
    >
      <div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.5rem' }}>
        <button onClick={() => void request.execute({ url: '/users' })}>
          Load
        </button>
        <button onClick={() => void request.execute({ url: '/error' })}>
          Fail
        </button>
        <button onClick={() => void request.execute({ url: '/slow' })}>
          Load slow
        </button>
        <button disabled={!request.loading} onClick={request.abort}>
          Cancel
        </button>
      </div>
      <output aria-live="polite">{output}</output>
    </section>
  );
}

专题 ​

状态与资源所有权 · 失败与取消边界

基于 Apache License 2.0 发布。