大家好!
我一直在開發一個輕量級的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 鉤子管理:
以下是 api-refetch 中的要點以及對 useAsync.tsx 中程式碼相關部分的簡短引用。
// 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 <= 0) return; // Revalidation is disabled if (!isEnabled || !enabled) return; // Hook is disabled if (isLoading) return; // Fetch is already in progress if (!isSuccess || !fetchedDateTime) return; // Should retry either of revalidate if (!(cacheEnabled || storeEnabled)) return; // Useless to revalidate if caching is disabled const timeout = setTimeout(() => { fetch(...storedArgsRef.current); }, revalidateTime); return () => clearTimeout(timeout); }, [ /* dependencies */ ] );
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 */ ] );
// 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 */ ] );
查看完整程式碼,其中包含本機儲存邏輯、查詢失效等:
如果您有興趣,請隨意嘗試、回報問題或做出貢獻。非常感謝任何反饋!
複製程式碼或編碼(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 <= 0) return; // Revalidation is disabled if (!isEnabled || !enabled) return; // Hook is disabled if (isLoading) return; // Fetch is already in progress if (!isSuccess || !fetchedDateTime) return; // Should retry either of revalidate if (!(cacheEnabled || storeEnabled)) return; // Useless to revalidate if caching is disabled const timeout = setTimeout(() => { fetch(...storedArgsRef.current); }, revalidateTime); return () => clearTimeout(timeout); }, [ /* dependencies */ ] );
就是這樣!嘗試一下,然後讓我知道進展如何。 GitHub 上非常歡迎提供回饋、問題或貢獻。
GitHub: api-refetch
編碼愉快!
以上是React 中用於非同步資料擷取和快取的輕量級 Hook 展示的詳細內容。更多資訊請關注PHP中文網其他相關文章!