diff --git a/packages/react-query/src/QueryErrorResetBoundary.tsx b/packages/react-query/src/QueryErrorResetBoundary.tsx index 910215bcb6..3e9d79a5d9 100644 --- a/packages/react-query/src/QueryErrorResetBoundary.tsx +++ b/packages/react-query/src/QueryErrorResetBoundary.tsx @@ -3,26 +3,26 @@ import * as React from 'react' // CONTEXT export type QueryErrorResetFunction = () => void -export type QueryErrorIsResetFunction = () => boolean +export type QueryErrorGetResetIdFunction = () => number export type QueryErrorClearResetFunction = () => void export interface QueryErrorResetBoundaryValue { clearReset: QueryErrorClearResetFunction - isReset: QueryErrorIsResetFunction + getResetId: QueryErrorGetResetIdFunction reset: QueryErrorResetFunction } function createValue(): QueryErrorResetBoundaryValue { - let isReset = false + const resetIdRef = { current: 0 } return { clearReset: () => { - isReset = false + resetIdRef.current = 0 }, reset: () => { - isReset = true + resetIdRef.current += 1 }, - isReset: () => { - return isReset + getResetId: () => { + return resetIdRef.current }, } } diff --git a/packages/react-query/src/useBaseQuery.ts b/packages/react-query/src/useBaseQuery.ts index a88f7d40fb..b5583a2451 100644 --- a/packages/react-query/src/useBaseQuery.ts +++ b/packages/react-query/src/useBaseQuery.ts @@ -96,75 +96,28 @@ export function useBaseQuery< ), ) - // note: this must be called before useSyncExternalStore - const result = observer.getOptimisticResult(defaultedOptions) + observer.setOptions(defaultedOptions, { isNewCacheEntry }) - const shouldSubscribe = !isRestoring && options.subscribed !== false - React.useSyncExternalStore( - React.useCallback( - (onStoreChange) => { - const unsubscribe = shouldSubscribe - ? observer.subscribe(notifyManager.batchCalls(onStoreChange)) - : noop - - // Update result to make sure we did not miss any query updates - // between creating the observer and subscribing to it. - observer.updateResult() - - return unsubscribe - }, - [observer, shouldSubscribe], - ), - () => observer.getCurrentResult(), - () => observer.getCurrentResult(), - ) + const result = observer.getOptimisticResult(defaultedOptions) React.useEffect(() => { - observer.setOptions(defaultedOptions) - }, [defaultedOptions, observer]) + errorResetBoundary.clearReset() + }, [errorResetBoundary]) - // Handle suspense - if (shouldSuspend(defaultedOptions, result)) { - throw fetchOptimistic(defaultedOptions, observer, errorResetBoundary) - } + React.useEffect(() => { + observer.subscribe(notifyManager.batchCalls(() => {})) + }, [observer]) - // Handle error boundary - if ( - getHasError({ - result, - errorResetBoundary, - throwOnError: defaultedOptions.throwOnError, - query, - suspense: defaultedOptions.suspense, - }) - ) { - throw result.error + if (shouldSuspend(defaultedOptions, result, isRestoring)) { + return fetchOptimistic(defaultedOptions, observer, errorResetBoundary) } - ;(client.getDefaultOptions().queries as any)?._experimental_afterQuery?.( - defaultedOptions, - result, - ) - if ( - defaultedOptions.experimental_prefetchInRender && - !environmentManager.isServer() && - willFetch(result, isRestoring) + willFetch(result, isRestoring) && + defaultedOptions._optimisticResults !== 'optimistic' ) { - const promise = isNewCacheEntry - ? // Fetch immediately on render in order to ensure `.promise` is resolved even if the component is unmounted - fetchOptimistic(defaultedOptions, observer, errorResetBoundary) - : // subscribe to the "cache promise" so that we can finalize the currentThenable once data comes in - query?.promise - - promise?.catch(noop).finally(() => { - // `.updateResult()` will trigger `.#currentThenable` to finalize - observer.updateResult() - }) + observer.fetchOptimistic(defaultedOptions) } - // Handle result property usage tracking - return !defaultedOptions.notifyOnChangeProps - ? observer.trackResult(result) - : result + return result }