11import { getContext , setContext , unstate } from 'svelte' ;
22import { ConvexClient } from 'convex/browser' ;
3- import type { FunctionReference , FunctionArgs , FunctionReturnType } from 'convex/server' ;
3+ import {
4+ type FunctionReference ,
5+ type FunctionArgs ,
6+ type FunctionReturnType ,
7+ getFunctionName
8+ } from 'convex/server' ;
49import { convexToJson , type Value } from 'convex/values' ;
10+ import { BROWSER } from 'esm-env' ;
511
612const _contextKey = '$$_convexClient' ;
713
@@ -26,8 +32,7 @@ export const setupConvex = (url: string) => {
2632
2733// SvelteKit provides `import { browser } from $app/environment` but this is only
2834// accurate in application code. So use a runtime conditional instead.
29- // https://github.com/sveltejs/kit/issues/5879
30- const isBrowser = typeof window !== 'undefined' ;
35+ const isBrowser = BROWSER ;
3136
3237const client = new ConvexClient ( url , { disabled : ! isBrowser } ) ;
3338setConvexClientContext ( client ) ;
@@ -70,41 +75,50 @@ export function useQuery<Query extends FunctionReference<'query'>>(
7075// mutations on a reactive object. Is this a good idea?
7176
7277const state : {
78+ // The
7379result : FunctionReturnType < Query > | Error | undefined ;
74- argsForLastResult : FunctionArgs < Query > ;
80+ // The last result we actually received, if this query has ever received one.
7581lastResult : FunctionReturnType < Query > | Error | undefined ;
82+ // The args (query key) of the last result that was received.
83+ argsForLastResult : FunctionArgs < Query > ;
7684} = $state ( {
7785result : undefined ,
7886argsForLastResult : undefined ,
7987lastResult : undefined
8088} ) ;
8189
82- // When args change, unsubscribe and resubscribe.
90+ // When args change we need to unsubscribe and resubscribe.
8391$effect ( ( ) => {
8492const argsObject = parseArgs ( args ) ;
85- state . result = undefined ;
86-
8793const unsubscribe = client . onUpdate ( query , argsObject , ( dataFromServer ) => {
88- // TODO is this helpful? (saving the original from being made reactive)
94+ // TODO is this helpful? (preventing the original from being made reactive)
8995// (note we're potentially copying error objects here)
9096const copy = structuredClone ( dataFromServer ) ;
9197
92- // TODO can/should each property be frozen?
9398state . result = copy ;
9499state . argsForLastResult = argsObject ;
95100state . lastResult = copy ;
96101} ) ;
97102return unsubscribe ;
98103} ) ;
99104
100- const sameArgs = $derived (
105+ // Are the args (the query key) the same as the last args we received a result for?
106+ const sameArgsAsLastResult = $derived (
101107! ! state . argsForLastResult &&
102108JSON . stringify ( convexToJson ( state . argsForLastResult ) ) ===
103109JSON . stringify ( convexToJson ( parseArgs ( args ) ) )
104110) ;
105- const useStale = $derived ( ! ! ( options . useResultFromPreviousArguments && state . lastResult ) ) ;
106- const result = $derived ( useStale ? state . lastResult : state . result ) ;
107- const isStale = $derived ( useStale && ! sameArgs ) ;
111+ const staleAllowed = $derived ( ! ! ( options . useResultFromPreviousArguments && state . lastResult ) ) ;
112+
113+ // This value updates before the effect runs.
114+ const syncResult : FunctionReturnType < Query > | undefined = $derived (
115+ ! client . disabled && client . client . localQueryResult ( getFunctionName ( query ) , parseArgs ( args ) )
116+ ) ;
117+
118+ const result = $derived (
119+ syncResult !== undefined ? syncResult : staleAllowed ? state . lastResult : undefined
120+ ) ;
121+ const isStale = $derived ( syncResult === undefined && staleAllowed && ! sameArgsAsLastResult ) ;
108122const data = $derived . by ( ( ) => {
109123if ( result instanceof Error ) {
110124return undefined ;
@@ -118,7 +132,7 @@ export function useQuery<Query extends FunctionReference<'query'>>(
118132return undefined ;
119133} ) ;
120134
121- // Cast to promise we're limiting ourselves to sensible values .
135+ // This TypeScript cast makes data not undefined if error and isLoading are checked first .
122136return {
123137get data ( ) {
124138return data ;
0 commit comments