1 Commits

Author SHA1 Message Date
Kristaps Fabians Geikins c751b3bd8a fix: ensuring useQuery immediately returns results from cache, to prevent hydration errors 2022-12-12 11:59:50 +02:00
2 changed files with 30 additions and 33 deletions
+30 -33
View File
@@ -21,6 +21,7 @@ import {
ObservableSubscription,
TypedDocumentNode,
ApolloError,
NetworkStatus
} from '@apollo/client/core'
import { throttle, debounce } from 'throttle-debounce'
import { useApolloClient } from './useApolloClient'
@@ -170,45 +171,20 @@ export function useQueryImpl<
// SSR
let firstResolve: (() => void) | undefined
let firstResolveTriggered = false
let firstReject: ((apolloError: ApolloError) => void) | undefined
let firstRejectError: undefined | ApolloError
const tryFirstResolve = () => {
firstResolveTriggered = true
if (firstResolve) firstResolve()
}
const tryFirstReject = (apolloError: ApolloError) => {
firstRejectError = apolloError
if (firstReject) firstReject(apolloError)
}
const resetFirstResolveReject = () => {
firstResolve = undefined
firstReject = undefined
firstResolveTriggered = false
firstRejectError = undefined
stop()
}
vm && onServerPrefetch?.(() => {
if (!isEnabled.value || (isServer && currentOptions.value?.prefetch === false)) return
return new Promise<void>((resolve, reject) => {
firstResolve = () => {
resetFirstResolveReject()
resolve()
firstResolve = undefined
firstReject = undefined
}
firstReject = (apolloError: ApolloError) => {
resetFirstResolveReject()
reject(apolloError)
}
if (firstResolveTriggered) {
firstResolve()
} else if (firstRejectError) {
firstReject(firstRejectError)
firstResolve = undefined
firstReject = undefined
}
}).then(stop).catch(stop)
})
@@ -221,6 +197,7 @@ export function useQueryImpl<
const query: Ref<ObservableQuery<TResult, TVariables> | null | undefined> = ref()
let observer: ObservableSubscription | undefined
let started = false
let isFirstRun = true
/**
* Starts watching the query
@@ -230,7 +207,7 @@ export function useQueryImpl<
started || !isEnabled.value ||
(isServer && currentOptions.value?.prefetch === false)
) {
tryFirstResolve()
if (firstResolve) firstResolve()
return
}
@@ -258,12 +235,26 @@ export function useQueryImpl<
addSubscribeToMore(item)
}
}
isFirstRun = false
}
function startQuerySubscription () {
if (observer && !observer.closed) return
if (!query.value) return
// If hydrating already finished queries, just handle result immediately
if (!isServer && isFirstRun) {
const currentResult = query.value.getCurrentResult()
if (currentResult) {
if (currentResult.networkStatus === NetworkStatus.ready) {
onNextResult(currentResult)
} else if (currentResult.networkStatus === NetworkStatus.error && currentResult.error) {
onError(currentResult.error)
}
}
}
// Create subscription
observer = query.value.subscribe({
next: onNextResult,
@@ -284,7 +275,10 @@ export function useQueryImpl<
processError(resultErrorsToApolloError(queryResult.errors))
}
tryFirstResolve()
if (firstResolve) {
firstResolve()
stop()
}
}
function processNextResult (queryResult: ApolloQueryResult<TResult>) {
@@ -304,7 +298,10 @@ export function useQueryImpl<
processNextResult((query.value as ObservableQuery<TResult, TVariables>).getCurrentResult())
}
processError(apolloError)
tryFirstReject(apolloError)
if (firstReject) {
firstReject(apolloError)
stop()
}
// The observable closes the sub if an error occurs
resubscribeToQuery()
}
@@ -331,7 +328,7 @@ export function useQueryImpl<
* Stop watching the query
*/
function stop () {
tryFirstResolve()
if (firstResolve) firstResolve()
if (!started) return
started = false
loading.value = false