Skip to content

React

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

选择入口

需求入口应用负责
点击发送 HTTPuseFetcherURL、Fetcher 和结果提取器;结果从 result 读取,不从 execute 返回值读取。
执行其他 Promise APIuseExecutePromiseSupplier,并将其 controller signal 传给 I/O。
查询变化时请求useQuery / useFetcherQuery初始/响应式 query;普通查询 Hook 默认自动执行。
输入时延迟搜索防抖 Hook必填延迟;定时器 cancel() 与活动请求 abort() 相互独立。
包装现有服务API Hook 工厂服务对象和方法;在渲染外创建 Hook 集合。
只记录其他系统的状态usePromiseState执行、清理和旧结果抑制由状态 Hook 外部负责。

完整安装前提

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

本参考针对 5.0.0。库包声明 Node >=18.20.8;仓库开发要求 Node >=20.20.2、pnpm 10.34.5。命令包含递归内部 peer,包括经 Wow/React/CoSec 引入的包;直接运行依赖自动安装。 外部 peer 范围为 React/ReactDOM ^19.2.8;即使不使用某项功能,仍是安装前提。消费者无需复制仓库的 React Compiler 工具链。

可运行核心示例

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

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 发布。