@snowykami/use-async-task
v0.0.3
Published
A lightweight React Hook for managing complex async task states with global sharing, caching, retry, and race condition control.
Maintainers
Readme
@snowykami/use-async-task
一个轻量的 React Hook,用于管理复杂异步任务的状态。支持全局共享、缓存、轮询、重试与竞态控制。
核心特性
- 🌍 跨组件共享状态 - 多个组件使用相同
taskKey会自动共享同一份任务状态 - 💾 智能缓存 - 可配置的缓存时间,避免重复请求相同数据
- 🔄 自动重试 - 内置失败重试机制,支持可配置的重试次数
- ⚡ 竞态控制 - 快速请求时仅应用最后一次的请求结果,旧请求自动丢弃
- 🔁 轮询支持 - 内置轮询间隔,支持定时自动刷新数据
- 🎯 完整类型支持 - 100% TypeScript,提供完整的类型定义
- 📦 超轻量 - 0 外部依赖,仅依赖 React
安装
npm install @snowykami/use-async-task
# 或者使用 yarn
yarn add @snowykami/use-async-task
# 或者使用 pnpm
pnpm add @snowykami/use-async-task快速开始
import { useAsyncTask } from '@snowykami/use-async-task';
function MyComponent() {
const { data, loading, error, execute } = useAsyncTask(
async (userId: string) => {
const res = await fetch(`/api/users/${userId}`);
return res.json();
},
{
immediate: false,
maxRetries: 2,
cacheTime: 10000, // 10秒缓存
taskKey: (userId) => `user-${userId}`,
}
);
return (
<div>
{loading && <p>加载中...</p>}
{error && <p>错误: {error}</p>}
{data && <p>用户: {data.name}</p>}
<button onClick={() => execute('123')}>获取用户 123</button>
</div>
);
}API 文档
useAsyncTask(action, options?, initialTaskKey?)
参数
action(...args: Args) => Promise<T>- 要执行的异步函数
- 接收
execute()传入的参数
options(可选){ // 挂载时或依赖变化时是否自动执行 immediate?: boolean; // 依赖列表(类似 useEffect) dependencies?: DependencyList; // 依赖变化时获取最新参数 getArgs?: () => Args; // 轮询间隔(毫秒),0 表示不轮询 pollingInterval?: number; // 最大重试次数 maxRetries?: number; // 缓存时间(毫秒),0 表示不缓存 cacheTime?: number; // 任务标识 // - 字符串:固定 key // - 函数:根据参数动态生成 key taskKey?: string | ((...args: Args) => string); }initialTaskKey(可选)- 初始任务 key(被
options.taskKey覆盖)
- 初始任务 key(被
返回值
{
// 状态属性
data: T | null; // 解析后的数据
loading: boolean; // 加载状态
error: TError | null; // 错误对象(如果有)
retryCount: number; // 重试次数
lastUpdated: number | null; // 最后更新时间戳
// 方法
execute: (...args: Args) => Promise<T | void>; // 手动执行任务
cancel: () => void; // 取消当前请求
reset: () => void; // 重置为初始状态
}使用示例
1. 跨组件共享状态
使用相同 taskKey 的多个组件自动共享状态:
// 组件 A
const { data: user } = useAsyncTask(
(id: string) => fetchUser(id),
{
maxRetries: 3,
taskKey: (id) => `user-${id}`,
}
);
// 组件 B(并行运行)
const { data: user } = useAsyncTask(
(id: string) => fetchUser(id),
{
maxRetries: 3,
taskKey: (id) => `user-${id}`, // 相同的 key!
}
);
// 两个组件自动同步,当数据更新时一起重新渲染2. 依赖变化时自动刷新
const [page, setPage] = useState(1);
const { data: users } = useAsyncTask(
(p: number) => fetchUsers(p),
{
immediate: true,
dependencies: [page],
getArgs: () => [page] as const,
taskKey: (p) => `users-page-${p}`,
}
);
// 改变 page 时自动触发新请求3. 搜索 + 缓存 + 竞态控制
const [query, setQuery] = useState('');
const { data: results } = useAsyncTask(
async (q: string) => searchUsers(q),
{
immediate: true,
dependencies: [query],
getArgs: () => [query] as const,
maxRetries: 1,
cacheTime: 30000, // 缓存 30 秒
taskKey: (q) => `search-${q}`,
}
);
// 快速输入:只处理最后一次搜索
// 重复搜索:30秒内使用缓存4. 轮询 / 定时刷新
const { data: stats } = useAsyncTask(
() => fetchStats(),
{
immediate: true,
pollingInterval: 5000, // 每 5 秒刷新一次
taskKey: 'dashboard-stats',
}
);5. 手动表单提交
const { loading, error, execute } = useAsyncTask(
async (formData: FormData) => submitForm(formData),
{ immediate: false } // 不自动执行
);
const handleSubmit = async (data: FormData) => {
const result = await execute(data);
if (result) console.log('提交成功!');
};全局状态共享原理
Hook 维护一个全局任务注册表,每个 taskKey 映射到一个共享状态:
taskKey: 'user-123'
└─ TaskRecord
├─ state: { data, loading, error, ... }
├─ listeners: Set<Listener> (所有订阅的组件)
└─ [竞态控制信息]当任何组件更新此状态时,所有订阅的组件自动重新渲染。
竞态控制原理
当多个请求同时进行时:
- 每个请求获得一个序列号
- 只有最新请求的结果会被应用
- 旧请求的结果自动被丢弃
这确保 UI 总是显示最新请求的结果。
缓存策略
在每次 execute() 调用时检查缓存:
if (Date.now() - lastUpdated <= cacheTime) {
// 使用缓存数据,跳过请求
return cachedData;
} else {
// 缓存过期,发起新请求
// 用新数据更新缓存
}不同的 taskKey 拥有独立的缓存。
最佳实践
使用具有描述性的 taskKey - 便于调试
taskKey: (userId) => `user-profile-${userId}` // ✓ 好 taskKey: (x) => `${x}` // ✗ 模糊使用 dependencies 时总是提供 getArgs
{ dependencies: [page], getArgs: () => [page] as const, // ✓ 提供新值 }根据数据新鲜度设置合适的缓存时间
cacheTime: 0, // 不缓存(实时数据) cacheTime: 5000, // 5 秒(不那么关键的数据) cacheTime: 300000, // 5 分钟(参考数据)对不稳定的端点使用重试
maxRetries: 0, // 不重试(关键且需要快速失败) maxRetries: 3, // 重试最多 3 次(标准)
浏览器支持
- ES2020+
- React 16.8+(需要 Hooks 支持)
许可证
MIT © snowykami
贡献
欢迎提交 Issue 和 PR!
更新日志
v1.0.0 (首次发布)
- 核心 Hook 实现
- 全局状态共享
- 缓存系统
- 重试逻辑
- 轮询支持
- 竞态控制
