diff --git a/examples/with-defer-stream-directives/src/App.jsx b/examples/with-defer-stream-directives/src/App.jsx index 3e29e59ded..4043a89ca1 100644 --- a/examples/with-defer-stream-directives/src/App.jsx +++ b/examples/with-defer-stream-directives/src/App.jsx @@ -21,7 +21,9 @@ const client = new Client({ function App() { return ( - + Loading...

}> + +
); } diff --git a/examples/with-defer-stream-directives/src/Songs.jsx b/examples/with-defer-stream-directives/src/Songs.jsx index a61b02a2ed..cd5dfb202d 100644 --- a/examples/with-defer-stream-directives/src/Songs.jsx +++ b/examples/with-defer-stream-directives/src/Songs.jsx @@ -13,6 +13,9 @@ const SONGS_QUERY = gql` firstVerse ...secondVerseFields @defer } + alphabet @stream(initialCount: 3) { + char + } } ${SecondVerseFragment} @@ -50,6 +53,9 @@ const LocationsList = () => { {data && ( <> + {data.alphabet.map(i => ( +
{i.char}
+ ))} )} diff --git a/packages/react-urql/src/hooks/cache.ts b/packages/react-urql/src/hooks/cache.ts index db6ddc3b77..52a162d181 100644 --- a/packages/react-urql/src/hooks/cache.ts +++ b/packages/react-urql/src/hooks/cache.ts @@ -1,7 +1,15 @@ import { pipe, subscribe } from 'wonka'; import type { Client, OperationResult } from '@urql/core'; -type CacheEntry = OperationResult | Promise | undefined; +export type FragmentPromise = Promise & { + _resolve: () => void; + _resolved: boolean; +}; +type CacheEntry = + | OperationResult + | Promise + | FragmentPromise + | undefined; interface Cache { get(key: number): CacheEntry; diff --git a/packages/react-urql/src/hooks/useFragment.ts b/packages/react-urql/src/hooks/useFragment.ts index e612110c79..3913eadffc 100644 --- a/packages/react-urql/src/hooks/useFragment.ts +++ b/packages/react-urql/src/hooks/useFragment.ts @@ -19,6 +19,7 @@ import type { import { useClient } from '../context'; import { useRequest } from './useRequest'; +import type { FragmentPromise } from './cache'; import { getCacheForClient } from './cache'; import { hasDepsChanged } from './state'; @@ -172,7 +173,12 @@ export function useFragment( cache.set(request.key, newResult.data as any); return { data: newResult.data as any, fetching: false }; } else if (suspense) { - const promise = new Promise(() => {}); + let _resolve; + const promise = new Promise(res => { + _resolve = res; + }) as FragmentPromise; + promise._resolve = _resolve; + promise._resolved = false; cache.set(request.key, promise); throw promise; } else { @@ -182,6 +188,14 @@ export function useFragment( throw cached; } + if ( + '_resolve' in cached && + '_resolved' in cached && + !cached._resolved && + typeof cached._resolve == 'function' + ) { + cached._resolve(); + } return { fetching: false, data: (cached as OperationResult).data }; }, [cache, request]