@tanstack/solid-query 5.0.0-beta.9 → 5.0.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { notifyManager, QueryClient as QueryClient$1, MutationObserver, QueriesObserver, hydrate, QueryObserver, InfiniteQueryObserver } from '@tanstack/query-core';
2
2
  export * from '@tanstack/query-core';
3
- import { batch, createContext, useContext, onMount, onCleanup, createMemo, createSignal, createComputed, on, createResource } from 'solid-js';
3
+ import { batch, createContext, useContext, createRenderEffect, onCleanup, createMemo, createSignal, createComputed, on, mergeProps, createResource, onMount, untrack } from 'solid-js';
4
4
  import { createComponent, isServer } from 'solid-js/web';
5
5
  import { createStore, unwrap, reconcile } from 'solid-js/store';
6
6
 
@@ -20,17 +20,17 @@ var useQueryClient = (queryClient) => {
20
20
  if (!client) {
21
21
  throw new Error("No QueryClient set, use QueryClientProvider to set one");
22
22
  }
23
- return client;
23
+ return client();
24
24
  };
25
25
  var QueryClientProvider = (props) => {
26
- onMount(() => {
26
+ createRenderEffect((unmount) => {
27
+ unmount?.();
27
28
  props.client.mount();
29
+ return props.client.unmount.bind(props.client);
28
30
  });
29
31
  onCleanup(() => props.client.unmount());
30
32
  return createComponent(QueryClientContext.Provider, {
31
- get value() {
32
- return props.client;
33
- },
33
+ value: () => props.client,
34
34
  get children() {
35
35
  return props.children;
36
36
  }
@@ -44,6 +44,9 @@ function shouldThrowError(throwError, params) {
44
44
  }
45
45
  return !!throwError;
46
46
  }
47
+ var IsRestoringContext = createContext(() => false);
48
+ var useIsRestoring = () => useContext(IsRestoringContext);
49
+ var IsRestoringProvider = IsRestoringContext.Provider;
47
50
 
48
51
  // src/createBaseQuery.ts
49
52
  function reconcileFn(store, result, reconcileOption) {
@@ -77,21 +80,31 @@ var hydrateableObserverResult = (query, result) => {
77
80
  };
78
81
  function createBaseQuery(options, Observer, queryClient) {
79
82
  const client = createMemo(() => useQueryClient(queryClient?.()));
80
- const defaultedOptions = client().defaultQueryOptions(options());
81
- defaultedOptions._optimisticResults = "optimistic";
82
- defaultedOptions.structuralSharing = false;
83
- if (isServer) {
84
- defaultedOptions.retry = false;
85
- defaultedOptions.throwOnError = true;
86
- }
87
- const observer = new Observer(client(), defaultedOptions);
83
+ const isRestoring = useIsRestoring();
84
+ const defaultedOptions = createMemo(
85
+ () => mergeProps(client().defaultQueryOptions(options()), {
86
+ get _optimisticResults() {
87
+ return isRestoring() ? "isRestoring" : "optimistic";
88
+ },
89
+ structuralSharing: false,
90
+ ...isServer && { retry: false, throwOnError: true }
91
+ })
92
+ );
93
+ const [observer, setObserver] = createSignal(
94
+ new Observer(client(), untrack(defaultedOptions))
95
+ );
96
+ createComputed(
97
+ on(client, (c) => setObserver(new Observer(c, defaultedOptions())), {
98
+ defer: true
99
+ })
100
+ );
88
101
  const [state, setState] = createStore(
89
- observer.getOptimisticResult(defaultedOptions)
102
+ observer().getOptimisticResult(defaultedOptions())
90
103
  );
91
104
  const createServerSubscriber = (resolve, reject) => {
92
- return observer.subscribe((result) => {
105
+ return observer().subscribe((result) => {
93
106
  notifyManager.batchCalls(() => {
94
- const query = observer.getCurrentQuery();
107
+ const query = observer().getCurrentQuery();
95
108
  const unwrappedResult = hydrateableObserverResult(query, result);
96
109
  if (unwrappedResult.isError) {
97
110
  reject(unwrappedResult.error);
@@ -102,44 +115,36 @@ function createBaseQuery(options, Observer, queryClient) {
102
115
  });
103
116
  };
104
117
  const createClientSubscriber = () => {
105
- return observer.subscribe((result) => {
118
+ const obs = observer();
119
+ return obs.subscribe((result) => {
106
120
  notifyManager.batchCalls(() => {
107
- const reconcileOptions = observer.options.reconcile;
108
- if (queryResource()?.data && result.data && !queryResource.loading) {
109
- setState((store) => {
110
- return reconcileFn(
111
- store,
112
- result,
113
- reconcileOptions === void 0 ? "id" : reconcileOptions
114
- );
115
- });
121
+ const reconcileOptions = obs.options.reconcile;
122
+ setState((store) => {
123
+ return reconcileFn(
124
+ store,
125
+ result,
126
+ reconcileOptions === void 0 ? "id" : reconcileOptions
127
+ );
128
+ });
129
+ if (queryResource()?.data && result.data && !queryResource.loading && isRestoring())
116
130
  mutate(state);
117
- } else {
118
- setState((store) => {
119
- return reconcileFn(
120
- store,
121
- result,
122
- reconcileOptions === void 0 ? "id" : reconcileOptions
123
- );
124
- });
131
+ else
125
132
  refetch();
126
- }
127
133
  })();
128
134
  });
129
135
  };
130
136
  let unsubscribe = null;
131
137
  const [queryResource, { refetch, mutate }] = createResource(
132
138
  () => {
139
+ const obs = observer();
133
140
  return new Promise((resolve, reject) => {
134
- if (isServer) {
141
+ if (isServer)
135
142
  unsubscribe = createServerSubscriber(resolve, reject);
136
- } else {
137
- if (!unsubscribe) {
138
- unsubscribe = createClientSubscriber();
139
- }
140
- }
141
- if (!state.isLoading) {
142
- const query = observer.getCurrentQuery();
143
+ else if (!unsubscribe && !isRestoring())
144
+ unsubscribe = createClientSubscriber();
145
+ obs.updateResult();
146
+ if (!state.isLoading && !isRestoring()) {
147
+ const query = obs.getCurrentQuery();
143
148
  resolve(hydrateableObserverResult(query, state));
144
149
  }
145
150
  });
@@ -147,7 +152,9 @@ function createBaseQuery(options, Observer, queryClient) {
147
152
  {
148
153
  initialValue: state,
149
154
  // If initialData is provided, we resolve the resource immediately
150
- ssrLoadFrom: options().initialData ? "initial" : "server",
155
+ get ssrLoadFrom() {
156
+ return options().initialData ? "initial" : "server";
157
+ },
151
158
  get deferStream() {
152
159
  return options().deferStream;
153
160
  },
@@ -160,29 +167,43 @@ function createBaseQuery(options, Observer, queryClient) {
160
167
  * Note that this is only invoked on the client, for queries that were originally run on the server.
161
168
  */
162
169
  onHydrated(_k, info) {
170
+ const defaultOptions = defaultedOptions();
163
171
  if (info.value) {
164
172
  hydrate(client(), {
165
173
  queries: [
166
174
  {
167
- queryKey: defaultedOptions.queryKey,
168
- queryHash: defaultedOptions.queryHash,
175
+ queryKey: defaultOptions.queryKey,
176
+ queryHash: defaultOptions.queryHash,
169
177
  state: info.value
170
178
  }
171
179
  ]
172
180
  });
173
181
  }
174
- if (!unsubscribe) {
175
- const newOptions = { ...defaultedOptions };
176
- if (defaultedOptions.staleTime || !defaultedOptions.initialData) {
177
- newOptions.refetchOnMount = false;
178
- }
179
- observer.setOptions(newOptions);
180
- setState(observer.getOptimisticResult(newOptions));
181
- unsubscribe = createClientSubscriber();
182
+ if (unsubscribe)
183
+ return;
184
+ const newOptions = { ...defaultOptions };
185
+ if (defaultOptions.staleTime || !defaultOptions.initialData) {
186
+ newOptions.refetchOnMount = false;
182
187
  }
188
+ observer().setOptions(newOptions);
189
+ setState(observer().getOptimisticResult(newOptions));
190
+ unsubscribe = createClientSubscriber();
183
191
  }
184
192
  }
185
193
  );
194
+ createComputed(
195
+ on(
196
+ [isRestoring, observer],
197
+ ([restoring]) => {
198
+ const unsub = unsubscribe;
199
+ queueMicrotask(() => unsub?.());
200
+ unsubscribe = null;
201
+ if (!restoring)
202
+ refetch();
203
+ },
204
+ { defer: true }
205
+ )
206
+ );
186
207
  onCleanup(() => {
187
208
  if (unsubscribe) {
188
209
  unsubscribe();
@@ -191,8 +212,11 @@ function createBaseQuery(options, Observer, queryClient) {
191
212
  });
192
213
  createComputed(
193
214
  on(
194
- () => client().defaultQueryOptions(options()),
195
- () => observer.setOptions(client().defaultQueryOptions(options())),
215
+ [observer, defaultedOptions],
216
+ ([obs, opts]) => {
217
+ obs.setOptions(opts);
218
+ setState(obs.getOptimisticResult(opts));
219
+ },
196
220
  {
197
221
  // Defer because we don't need to trigger on first render
198
222
  // This only cares about changes to options after the observer is created
@@ -204,9 +228,10 @@ function createBaseQuery(options, Observer, queryClient) {
204
228
  on(
205
229
  () => state.status,
206
230
  () => {
207
- if (state.isError && !state.isFetching && shouldThrowError(observer.options.throwOnError, [
231
+ const obs = observer();
232
+ if (state.isError && !state.isFetching && !isRestoring() && shouldThrowError(obs.options.throwOnError, [
208
233
  state.error,
209
- observer.getCurrentQuery()
234
+ obs.getCurrentQuery()
210
235
  ])) {
211
236
  throw state.error;
212
237
  }
@@ -252,9 +277,9 @@ function createInfiniteQuery(options, queryClient) {
252
277
  );
253
278
  }
254
279
  function createMutation(options, queryClient) {
255
- const client = useQueryClient(queryClient?.());
280
+ const client = createMemo(() => useQueryClient(queryClient?.()));
256
281
  const observer = new MutationObserver(
257
- client,
282
+ client(),
258
283
  options()
259
284
  );
260
285
  const mutate = (variables, mutateOptions) => {
@@ -303,43 +328,114 @@ function useIsMutating(filters, queryClient) {
303
328
  return mutations;
304
329
  }
305
330
  function createQueries(queriesOptions, queryClient) {
306
- const client = useQueryClient(queryClient?.());
307
- const defaultedQueries = queriesOptions().queries.map((options) => {
308
- const defaultedOptions = client.defaultQueryOptions(options);
309
- defaultedOptions._optimisticResults = "optimistic";
310
- return defaultedOptions;
311
- });
331
+ const client = createMemo(() => useQueryClient(queryClient?.()));
332
+ const isRestoring = useIsRestoring();
333
+ const defaultedQueries = createMemo(
334
+ () => queriesOptions().queries.map(
335
+ (options) => mergeProps(client().defaultQueryOptions(options), {
336
+ get _optimisticResults() {
337
+ return isRestoring() ? "isRestoring" : "optimistic";
338
+ }
339
+ })
340
+ )
341
+ );
312
342
  const observer = new QueriesObserver(
313
- client,
314
- defaultedQueries,
343
+ client(),
344
+ defaultedQueries(),
315
345
  queriesOptions().combine ? {
316
346
  combine: queriesOptions().combine
317
347
  } : void 0
318
348
  );
319
349
  const [state, setState] = createStore(
320
- observer.getOptimisticResult(defaultedQueries)[1]()
350
+ observer.getOptimisticResult(defaultedQueries())[1]()
321
351
  );
322
- const unsubscribe = observer.subscribe((result) => {
323
- notifyManager.batchCalls(() => {
324
- setState(unwrap(result));
325
- })();
352
+ createRenderEffect(
353
+ on(
354
+ () => queriesOptions().queries.length,
355
+ () => setState(observer.getOptimisticResult(defaultedQueries())[1]())
356
+ )
357
+ );
358
+ const dataResources = createMemo(
359
+ on(
360
+ () => state.length,
361
+ () => state.map((queryRes) => {
362
+ const dataPromise = () => new Promise((resolve) => {
363
+ if (queryRes.isFetching && queryRes.isLoading)
364
+ return;
365
+ resolve(unwrap(queryRes.data));
366
+ });
367
+ return createResource(dataPromise);
368
+ })
369
+ )
370
+ );
371
+ batch(() => {
372
+ const dataResources_ = dataResources();
373
+ for (let index = 0; index < dataResources_.length; index++) {
374
+ const dataResource = dataResources_[index];
375
+ dataResource[1].mutate(() => unwrap(state[index].data));
376
+ dataResource[1].refetch();
377
+ }
378
+ });
379
+ let taskQueue = [];
380
+ const subscribeToObserver = () => observer.subscribe((result) => {
381
+ taskQueue.push(() => {
382
+ batch(() => {
383
+ const dataResources_ = dataResources();
384
+ for (let index = 0; index < dataResources_.length; index++) {
385
+ const dataResource = dataResources_[index];
386
+ const unwrappedResult = { ...unwrap(result[index]) };
387
+ setState(index, unwrap(unwrappedResult));
388
+ dataResource[1].mutate(() => unwrap(state[index].data));
389
+ dataResource[1].refetch();
390
+ }
391
+ });
392
+ });
393
+ queueMicrotask(() => {
394
+ const taskToRun = taskQueue.pop();
395
+ if (taskToRun)
396
+ taskToRun();
397
+ taskQueue = [];
398
+ });
399
+ });
400
+ let unsubscribe = () => void 0;
401
+ createComputed((cleanup) => {
402
+ cleanup?.();
403
+ unsubscribe = isRestoring() ? () => void 0 : subscribeToObserver();
404
+ return () => queueMicrotask(unsubscribe);
326
405
  });
327
406
  onCleanup(unsubscribe);
407
+ onMount(() => {
408
+ observer.setQueries(
409
+ defaultedQueries(),
410
+ queriesOptions().combine ? {
411
+ combine: queriesOptions().combine
412
+ } : void 0,
413
+ { listeners: false }
414
+ );
415
+ });
328
416
  createComputed(() => {
329
- const updatedQueries = queriesOptions().queries.map((options) => {
330
- const defaultedOptions = client.defaultQueryOptions(options);
331
- defaultedOptions._optimisticResults = "optimistic";
332
- return defaultedOptions;
333
- });
334
417
  observer.setQueries(
335
- updatedQueries,
418
+ defaultedQueries(),
336
419
  queriesOptions().combine ? {
337
420
  combine: queriesOptions().combine
338
421
  } : void 0,
339
422
  { listeners: false }
340
423
  );
341
424
  });
342
- return state;
425
+ const handler = (index) => ({
426
+ get(target, prop) {
427
+ if (prop === "data") {
428
+ return dataResources()[index][0]();
429
+ }
430
+ return Reflect.get(target, prop);
431
+ }
432
+ });
433
+ const getProxies = () => state.map((s, index) => {
434
+ return new Proxy(s, handler(index));
435
+ });
436
+ const [proxifiedState, setProxifiedState] = createStore(getProxies());
437
+ createRenderEffect(() => setProxifiedState(getProxies()));
438
+ return proxifiedState;
343
439
  }
344
440
 
345
- export { QueryClient, QueryClientContext, QueryClientProvider, createInfiniteQuery, createMutation, createQueries, createQuery, queryOptions, useIsFetching, useIsMutating, useQueryClient };
441
+ export { IsRestoringProvider, QueryClient, QueryClientContext, QueryClientProvider, createInfiniteQuery, createMutation, createQueries, createQuery, queryOptions, useIsFetching, useIsMutating, useIsRestoring, useQueryClient };
package/package.json CHANGED
@@ -1,10 +1,14 @@
1
1
  {
2
2
  "name": "@tanstack/solid-query",
3
- "version": "5.0.0-beta.9",
3
+ "version": "5.0.0-rc.0",
4
4
  "description": "Primitives for managing, caching and syncing asynchronous and remote data in Solid",
5
5
  "author": "tannerlinsley",
6
6
  "license": "MIT",
7
- "repository": "tanstack/query",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/TanStack/query.git",
10
+ "directory": "packages/solid-query"
11
+ },
8
12
  "homepage": "https://tanstack.com/query",
9
13
  "funding": {
10
14
  "type": "github",
@@ -44,7 +48,7 @@
44
48
  ],
45
49
  "dependencies": {
46
50
  "solid-js": "^1.7.8",
47
- "@tanstack/query-core": "5.0.0-beta.9"
51
+ "@tanstack/query-core": "5.0.0-rc.0"
48
52
  },
49
53
  "devDependencies": {
50
54
  "tsup-preset-solid": "^2.0.1",
@@ -1,10 +1,15 @@
1
- import { createContext, onCleanup, onMount, useContext } from 'solid-js'
1
+ import {
2
+ createContext,
3
+ createRenderEffect,
4
+ onCleanup,
5
+ useContext,
6
+ } from 'solid-js'
2
7
  import type { QueryClient } from './QueryClient'
3
8
  import type { JSX } from 'solid-js'
4
9
 
5
- export const QueryClientContext = createContext<QueryClient | undefined>(
6
- undefined,
7
- )
10
+ export const QueryClientContext = createContext<
11
+ (() => QueryClient) | undefined
12
+ >(undefined)
8
13
 
9
14
  export const useQueryClient = (queryClient?: QueryClient) => {
10
15
  if (queryClient) {
@@ -16,7 +21,7 @@ export const useQueryClient = (queryClient?: QueryClient) => {
16
21
  throw new Error('No QueryClient set, use QueryClientProvider to set one')
17
22
  }
18
23
 
19
- return client
24
+ return client()
20
25
  }
21
26
 
22
27
  export type QueryClientProviderProps = {
@@ -27,13 +32,15 @@ export type QueryClientProviderProps = {
27
32
  export const QueryClientProvider = (
28
33
  props: QueryClientProviderProps,
29
34
  ): JSX.Element => {
30
- onMount(() => {
35
+ createRenderEffect<() => void>((unmount) => {
36
+ unmount?.()
31
37
  props.client.mount()
38
+ return props.client.unmount.bind(props.client)
32
39
  })
33
40
  onCleanup(() => props.client.unmount())
34
41
 
35
42
  return (
36
- <QueryClientContext.Provider value={props.client}>
43
+ <QueryClientContext.Provider value={() => props.client}>
37
44
  {props.children}
38
45
  </QueryClientContext.Provider>
39
46
  )