大家好!
我一直在开发一个轻量级的 React hook,我称之为 useAsync,它模仿 React Query 的一些基本功能(如获取、缓存、重试等),但以更紧凑的方式,易于定制的包。下面是其内部工作原理的快速分解,引用了相关的代码部分。如果您想查看完整代码,请前往存储库:
GitHub 上的完整源代码。
该钩子也可以在 npm 上作为 api-refetch.
为什么要自己制作钩子?
虽然 React Query 和 SWR 都是很棒的库,但出于以下几个原因,我想要一种更实用的方法:
轻量化
虽然 React Query 和 SWR 功能丰富,但它们可能相对较大(React Query ~2.2 MB,SWR ~620 kB)。 api-refetch 大约 250 kB,使其非常适合较小的应用程序,其中包大小是一个大问题。该挂钩意味着作为另一个库(Intlayer)的依赖项安装。因此,解决方案的大小是一个重要的考虑因素。易于定制和优化
我需要一些特定的功能,例如从本地存储存储/获取数据和使用简单的方法管理并行请求。
通过克隆存储库或将代码直接复制到您的项目中,您可以删除任何不需要的功能并仅保留您需要的功能。这不仅可以减少捆绑包大小,还可以最大限度地减少不必要的重新渲染和增加,为您提供根据您的特定要求量身定制的更精简、性能更高的解决方案。无所需提供商
我想避免使用 Context Provider 来使钩子全局化,并使其使用尽可能简单。所以我根据 Zustand 商店制作了 hooke 的一个版本(参见下面的示例)。学习练习
从头开始构建异步库是理解并发、缓存和状态管理内部结构的绝佳方法。
简而言之,滚动我自己的钩子是一个机会精确磨练我需要的功能(并跳过我不需要的功能),同时保持库小且易于理解。
涵盖的功能
React 钩子管理:
- 获取和状态管理:处理加载、错误、成功和获取状态。
- 缓存和存储:可选择缓存数据(通过底层的 React 状态或 Zustand)并提供本地存储支持。
- 重试和重新验证:可配置的重试限制和自动重新验证间隔。
- 激活和失效:根据其他查询或状态自动激活和失效查询。示例:用户登录时自动获取一些数据,并在用户注销时使其失效。
- 并行组件挂载获取:当多个组件同时挂载时,防止对同一资源同时发出多个请求。
代码如何运作
以下是 api-refetch 中的要点以及对 useAsync.tsx 中代码相关部分的简短引用。
1. 并行安装的获取和处理
- 代码片段:
// This map stores any in-progress Promise to avoid sending parallel requests // for the same resource across multiple components. const pendingPromises = new Map(); const fetch: T = async (...args) => { // Check if a request with the same key + args is already running if (pendingPromises.has(keyWithArgs)) { return pendingPromises.get(keyWithArgs); } // Otherwise, store a new Promise and execute const promise = (async () => { setQueryState(keyWithArgs, { isLoading: true }); // ...perform fetch here... })(); // Keep it in the map until it resolves or rejects pendingPromises.set(keyWithArgs, promise); return await promise; };
- 说明:在这里,我们将任何正在进行的提取存储在pendingPromises 映射中。当两个组件尝试同时获取相同的资源(通过具有相同的 keyWithArgs)时,第二个组件只会重用正在进行的请求,而不是进行重复的网络调用。
2. 重新验证
- 代码片段:
// Handle periodic revalidation if caching is enabled useEffect( () => { if (!revalidationEnabled || revalidateTime { fetch(...storedArgsRef.current); }, revalidateTime); return () => clearTimeout(timeout); }, [ /* dependencies */ ] );
- 说明:每当您启用重新验证时,api-refetch 都会检查缓存的数据是否早于指定的 revalidateTime。如果是,数据会在后台自动重新获取,以使您的 UI 保持同步,无需额外的手动触发。
3. 重试逻辑
- 代码片段:
useEffect( () => { const isRetryEnabled = errorCount > 0 && retryLimit > 0; const isRetryLimitReached = errorCount > retryLimit; if (!isEnabled || !enabled) return; // Hook is disabled if (!isRetryEnabled) return; // Retry is disabled if (isRetryLimitReached) return; // Retry limit has been reached if (!(cacheEnabled || storeEnabled)) return; // Useless to retry if caching is disabled if (isLoading) return; // Fetch is already in progress if (isSuccess) return; // Hook has already fetched successfully const timeout = setTimeout(() => { fetch(...storedArgsRef.current); }, retryTime); return () => clearTimeout(timeout); }, [ /* dependencies */ ] );
- 解释:发生错误时,挂钩会计算已发生的失败尝试次数。如果它仍然低于 retryLimit,它会自动等待 retryTime 毫秒,然后再重试。此过程将持续进行,直到成功获取数据或达到重试限制。
4. 自动获取
- 代码片段:
// Auto-fetch data on hook mount if autoFetch is true useEffect( () => { if (!autoFetch) return; // Auto-fetch is disabled if (!isEnabled || !enabled) return; // Hook is disabled if (isFetched && !isInvalidated) return; // Hook have already fetched or invalidated if (isLoading) return; // Fetch is already in progress fetch(...storedArgsRef.current); }, [ /* dependencies */ ] );
- 说明:将 autoFetch 设置为 true 时,钩子将在组件安装后立即自动运行异步函数,非常适合您始终希望加载数据的“即发即忘”场景。
查看 GitHub 上的完整源代码
查看完整代码,其中包括本地存储逻辑、查询失效等:
- 完整源代码
如果您有兴趣,请随意尝试、报告问题或做出贡献。非常感谢任何反馈!
使用示例
安装
复制代码或编码(repo)[https://github.com/aymericzip/api-refetch]
或者
// This map stores any in-progress Promise to avoid sending parallel requests // for the same resource across multiple components. const pendingPromises = new Map(); const fetch: T = async (...args) => { // Check if a request with the same key + args is already running if (pendingPromises.has(keyWithArgs)) { return pendingPromises.get(keyWithArgs); } // Otherwise, store a new Promise and execute const promise = (async () => { setQueryState(keyWithArgs, { isLoading: true }); // ...perform fetch here... })(); // Keep it in the map until it resolves or rejects pendingPromises.set(keyWithArgs, promise); return await promise; };
快速示例
// Handle periodic revalidation if caching is enabled useEffect( () => { if (!revalidationEnabled || revalidateTime { fetch(...storedArgsRef.current); }, revalidateTime); return () => clearTimeout(timeout); }, [ /* dependencies */ ] );
就是这样!尝试一下,然后让我知道进展如何。 GitHub 上非常欢迎提供反馈、问题或贡献。
GitHub: api-refetch
编码愉快!
以上是React 中用于异步数据获取和缓存的轻量级 Hook 展示的详细内容。更多信息请关注PHP中文网其他相关文章!

JavaScript字符串替换方法详解及常见问题解答 本文将探讨两种在JavaScript中替换字符串字符的方法:在JavaScript代码内部替换和在网页HTML内部替换。 在JavaScript代码内部替换字符串 最直接的方法是使用replace()方法: str = str.replace("find","replace"); 该方法仅替换第一个匹配项。要替换所有匹配项,需使用正则表达式并添加全局标志g: str = str.replace(/fi

本教程向您展示了如何将自定义的Google搜索API集成到您的博客或网站中,提供了比标准WordPress主题搜索功能更精致的搜索体验。 令人惊讶的是简单!您将能够将搜索限制为Y

因此,在这里,您准备好了解所有称为Ajax的东西。但是,到底是什么? AJAX一词是指用于创建动态,交互式Web内容的一系列宽松的技术。 Ajax一词,最初由Jesse J创造

本文系列在2017年中期进行了最新信息和新示例。 在此JSON示例中,我们将研究如何使用JSON格式将简单值存储在文件中。 使用键值对符号,我们可以存储任何类型的

利用轻松的网页布局:8个基本插件 jQuery大大简化了网页布局。 本文重点介绍了简化该过程的八个功能强大的JQuery插件,对于手动网站创建特别有用

核心要点 JavaScript 中的 this 通常指代“拥有”该方法的对象,但具体取决于函数的调用方式。 没有当前对象时,this 指代全局对象。在 Web 浏览器中,它由 window 表示。 调用函数时,this 保持全局对象;但调用对象构造函数或其任何方法时,this 指代对象的实例。 可以使用 call()、apply() 和 bind() 等方法更改 this 的上下文。这些方法使用给定的 this 值和参数调用函数。 JavaScript 是一门优秀的编程语言。几年前,这句话可

jQuery是一个很棒的JavaScript框架。但是,与任何图书馆一样,有时有必要在引擎盖下发现发生了什么。也许是因为您正在追踪一个错误,或者只是对jQuery如何实现特定UI感到好奇

该帖子编写了有用的作弊表,参考指南,快速食谱以及用于Android,BlackBerry和iPhone应用程序开发的代码片段。 没有开发人员应该没有他们! 触摸手势参考指南(PDF) Desig的宝贵资源


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

适用于 Eclipse 的 SAP NetWeaver 服务器适配器
将Eclipse与SAP NetWeaver应用服务器集成。

EditPlus 中文破解版
体积小,语法高亮,不支持代码提示功能

Dreamweaver Mac版
视觉化网页开发工具

记事本++7.3.1
好用且免费的代码编辑器

VSCode Windows 64位 下载
微软推出的免费、功能强大的一款IDE编辑器