Created
November 1, 2018 01:03
-
-
Save quisido/8df1bd1dbc1fe611df803c877d4e2815 to your computer and use it in GitHub Desktop.
React Suspense with the Fetch API
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const deepEqual = require('deep-equal'); | |
| interface FetchCache { | |
| fetch?: Promise<void>; | |
| error?: any; | |
| init: RequestInit | undefined; | |
| input: RequestInfo; | |
| response?: any; | |
| } | |
| const fetchCaches: FetchCache[] = []; | |
| const useFetch = (input: RequestInfo, init?: RequestInit | undefined) => { | |
| for (const fetchCache of fetchCaches) { | |
| // The request hasn't changed since the last call. | |
| if ( | |
| deepEqual(input, fetchCache.input) && | |
| deepEqual(init, fetchCache.init) | |
| ) { | |
| // If we logged an error during this fetch request, THROW the error. | |
| if (Object.prototype.hasOwnProperty.call(fetchCache, 'error')) { | |
| throw fetchCache.error; | |
| } | |
| // If we received a response to this fetch request, RETURN it. | |
| if (Object.prototype.hasOwnProperty.call(fetchCache, 'response')) { | |
| return fetchCache.response; | |
| } | |
| // If we do not have a response or error, THROW the promise. | |
| throw fetchCache.fetch; | |
| } | |
| } | |
| // The request is new or has changed. | |
| const fetchCache: FetchCache = { | |
| fetch: | |
| // Make the fetch request. | |
| fetch(input, init) | |
| // Parse the response. | |
| .then(response => { | |
| // Support JSON. | |
| if (Object.prototype.hasOwnProperty.call(response.headers, 'Content-Type')) { | |
| return response.json(); | |
| } | |
| // Not JSON. | |
| return response.text(); | |
| }) | |
| // Cache the response for when this component | |
| // attempts to render again later. | |
| .then(response => { | |
| fetchCache.response = response; | |
| }) | |
| // Cache the error for when this component | |
| // attempts to render again later. | |
| .catch(e => { | |
| fetchCache.error = e; | |
| }), | |
| init, | |
| input | |
| }; | |
| // Add this metadata to the memoization array. | |
| fetchCaches.push(fetchCache); | |
| // Throw the Promise! Suspense to the rescue! | |
| throw fetchCache.fetch; | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment