React
React Hook 将异步操作连接到一个挂载组件:状态、执行、查询驱动刷新及可选防抖。它们不提供共享响应缓存。显式操作从执行 Hook 开始;只有输入改变应发送请求时才使用自动查询。
选择入口
| 需求 | 入口 | 应用负责 |
|---|---|---|
| 点击发送 HTTP | useFetcher | URL、Fetcher 和结果提取器;结果从 result 读取,不从 execute 返回值读取。 |
| 执行其他 Promise API | useExecutePromise | Supplier,并将其 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>
);
}