Last active
November 25, 2024 04:51
-
-
Save wojtekmaj/da7fb5908cf30a9a91a1243c663dea91 to your computer and use it in GitHub Desktop.
Revisions
-
wojtekmaj revised this gist
Feb 26, 2024 . No changes.There are no files selected for viewing
-
wojtekmaj revised this gist
Feb 26, 2024 . No changes.There are no files selected for viewing
-
wojtekmaj created this gist
Feb 26, 2024 .There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,72 @@ /// <reference types="react/next" /> import { use as originalUse, useContext } from 'react'; const STATUS = { PENDING: 'pending', REJECTED: 'rejected', FULFILLED: 'fulfilled', } as const; type TState<T> = | { status: typeof STATUS.PENDING; promise: Promise<void> } | { status: typeof STATUS.REJECTED; error: Error } | { status: typeof STATUS.FULFILLED; result: T }; // eslint-disable-next-line @typescript-eslint/no-explicit-any const states = new Map<Promise<unknown>, TState<any>>(); function usePromiseFallback<T>(usable: Promise<T>): T { const existingState = states.get(usable); const state: TState<T> = existingState || (() => { const promise = usable .then((data) => { states.set(usable, { status: STATUS.FULFILLED, result: data, }); }) .catch((error) => { states.set(usable, { status: STATUS.REJECTED, error, }); }); const newState: TState<T> = { status: 'pending', promise: promise }; states.set(usable, newState); return newState; })(); switch (state.status) { case STATUS.PENDING: // Suspend the component while fetching throw state.promise; case STATUS.REJECTED: // Result is an error throw state.error; case STATUS.FULFILLED: // Result is a fulfilled promise return state.result; } } function useContextFallback<T>(context: React.Context<T>) { return useContext(context); } function useFallback<T>(usable: Promise<T> | React.Context<T>): T { if (usable instanceof Promise) { // eslint-disable-next-line react-hooks/rules-of-hooks return usePromiseFallback(usable); } // eslint-disable-next-line react-hooks/rules-of-hooks return useContextFallback(usable); } const use = originalUse || useFallback; export default use;