/// import { use as originalUse, useContext } from 'react'; const STATUS = { PENDING: 'pending', REJECTED: 'rejected', FULFILLED: 'fulfilled', } as const; type TState = | { status: typeof STATUS.PENDING; promise: Promise } | { 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, TState>(); function usePromiseFallback(usable: Promise): T { const existingState = states.get(usable); const state: TState = 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 = { 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(context: React.Context) { return useContext(context); } function useFallback(usable: Promise | React.Context): 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;