@tanstack/solid-query 5.102.8 → 5.103.1

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/dev.cjs CHANGED
@@ -4,8 +4,19 @@ let solid_js = require("solid-js");
4
4
  let solid_js_web = require("solid-js/web");
5
5
  let solid_js_store = require("solid-js/store");
6
6
  //#region src/QueryClientProvider.tsx
7
+ /**
8
+ * The context that `useQueryClient` reads from. `QueryClientProvider` is the normal way to set it.
9
+ */
7
10
  const QueryClientContext = (0, solid_js.createContext)(void 0);
8
11
  const queryClientContextError = "No QueryClient set, use QueryClientProvider to set one";
12
+ /**
13
+ * The `useQueryClient` hook returns the current `QueryClient` instance.
14
+ *
15
+ * @param queryClient - Use this to use a custom `QueryClient`. Otherwise, the one from the nearest context will
16
+ * be used.
17
+ * @returns The current `QueryClient` instance.
18
+ * @throws If no `queryClient` argument is passed and no `QueryClientProvider` is found in the component tree.
19
+ */
9
20
  const useQueryClient = (queryClient) => {
10
21
  if (queryClient) return queryClient;
11
22
  const client = (0, solid_js.useContext)(QueryClientContext);
@@ -21,6 +32,25 @@ const useQueryClientResolver = (queryClient) => {
21
32
  return contextClient();
22
33
  };
23
34
  };
35
+ /**
36
+ * Use the `QueryClientProvider` component to connect and provide a `QueryClient` to your application. Also
37
+ * calls `client.mount()`/`client.unmount()` as this component mounts/unmounts, which subscribes the client to
38
+ * focus/online events (resuming any paused mutations and refetching as needed when the app regains focus or
39
+ * comes back online).
40
+ *
41
+ * @returns The provided `children`, wrapped so they can read the `QueryClient` via `useQueryClient`.
42
+ *
43
+ * @example
44
+ * ```tsx
45
+ * import { QueryClient, QueryClientProvider } from '@tanstack/solid-query'
46
+ *
47
+ * const queryClient = new QueryClient()
48
+ *
49
+ * function App() {
50
+ * return <QueryClientProvider client={queryClient}>...</QueryClientProvider>
51
+ * }
52
+ * ```
53
+ */
24
54
  const QueryClientProvider = (props) => {
25
55
  (0, solid_js.createRenderEffect)((unmount) => {
26
56
  unmount?.();
@@ -38,7 +68,18 @@ const QueryClientProvider = (props) => {
38
68
  //#endregion
39
69
  //#region src/isRestoring.ts
40
70
  const IsRestoringContext = (0, solid_js.createContext)(() => false);
71
+ /**
72
+ * If you are using `PersistQueryClientProvider`, you can also use the `useIsRestoring` hook alongside it to
73
+ * check if a restore is currently in progress. `useQuery` and friends also check this internally to avoid
74
+ * race conditions between the restore and mounting queries.
75
+ *
76
+ * @returns An accessor that reads `true` while a persisted client is being restored, `false` otherwise.
77
+ */
41
78
  const useIsRestoring = () => (0, solid_js.useContext)(IsRestoringContext);
79
+ /**
80
+ * The Provider that `PersistQueryClientProvider` uses to signal whether a persisted client is currently
81
+ * being restored, read by `useIsRestoring`.
82
+ */
42
83
  const IsRestoringProvider = IsRestoringContext.Provider;
43
84
  //#endregion
44
85
  //#region src/useBaseQuery.ts
@@ -248,6 +289,165 @@ function useInfiniteQuery(options, queryClient) {
248
289
  }
249
290
  //#endregion
250
291
  //#region src/useMutation.ts
292
+ /**
293
+ * @param options - An accessor returning the {@link UseMutationOptions} to use.
294
+ * @param queryClient - An accessor for a custom `QueryClient`. Otherwise, the one from the nearest context
295
+ * will be used.
296
+ * @returns `mutate`/`mutateAsync` also accept per-call `onSuccess`/`onError`/`onSettled` callbacks as a second
297
+ * argument, useful for triggering call-site side effects (e.g. navigation) without coupling them to the shared
298
+ * mutation definition. Hook-level callbacks (passed to `options`) fire for every mutation; per-call callbacks
299
+ * fire only for the latest call you've made, and only while the component is still mounted — unmounting before
300
+ * the mutation settles removes the subscription and prevents them from firing.
301
+ *
302
+ * @example
303
+ * ```tsx
304
+ * import { useMutation, useQueryClient } from '@tanstack/solid-query'
305
+ *
306
+ * function TodoItem(props: { id: number }) {
307
+ * const queryClient = useQueryClient()
308
+ *
309
+ * const deleteTodoMutation = useMutation(() => ({
310
+ * mutationFn: deleteTodo,
311
+ * onSuccess: () => {
312
+ * queryClient.invalidateQueries({ queryKey: ['todos'] })
313
+ * },
314
+ * }))
315
+ *
316
+ * return (
317
+ * <button onClick={() => deleteTodoMutation.mutate({ id: props.id })} disabled={deleteTodoMutation.isPending}>
318
+ * Delete
319
+ * </button>
320
+ * )
321
+ * }
322
+ * ```
323
+ *
324
+ * @example
325
+ * Rendering the mutation's own state, rather than just firing it off:
326
+ * ```tsx
327
+ * import { Match, Switch } from 'solid-js'
328
+ * import { useMutation, useQueryClient } from '@tanstack/solid-query'
329
+ *
330
+ * function AddTodo() {
331
+ * const queryClient = useQueryClient()
332
+ *
333
+ * const addMutation = useMutation(() => ({
334
+ * mutationFn: addTodo,
335
+ * onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
336
+ * }))
337
+ *
338
+ * return (
339
+ * <Switch fallback={<button onClick={() => addMutation.mutate('Item')}>Add</button>}>
340
+ * <Match when={addMutation.isPending}>Adding todo...</Match>
341
+ * <Match when={addMutation.isError}>
342
+ * <div>An error occurred: {addMutation.error?.message}</div>
343
+ * <button onClick={() => addMutation.mutate('Item')}>Add</button>
344
+ * </Match>
345
+ * </Switch>
346
+ * )
347
+ * }
348
+ * ```
349
+ *
350
+ * @example
351
+ * Optimistic update via `onMutate`, rolling back on `onError`:
352
+ * ```tsx
353
+ * import { useMutation, useQueryClient } from '@tanstack/solid-query'
354
+ *
355
+ * function AddTodo() {
356
+ * const queryClient = useQueryClient()
357
+ *
358
+ * const addMutation = useMutation(() => ({
359
+ * mutationFn: addTodo,
360
+ * onMutate: async (newTodo) => {
361
+ * await queryClient.cancelQueries({ queryKey: ['todos'] })
362
+ * const previousTodos = queryClient.getQueryData<Array<string>>(['todos'])
363
+ *
364
+ * queryClient.setQueryData<Array<string>>(['todos'], (old) => [
365
+ * ...(old ?? []),
366
+ * newTodo,
367
+ * ])
368
+ *
369
+ * // Passed to `onError` as `onMutateResult` if the mutation fails.
370
+ * return { previousTodos }
371
+ * },
372
+ * onError: (_err, _newTodo, onMutateResult) => {
373
+ * queryClient.setQueryData(['todos'], onMutateResult?.previousTodos)
374
+ * },
375
+ * onSettled: () => {
376
+ * queryClient.invalidateQueries({ queryKey: ['todos'] })
377
+ * },
378
+ * }))
379
+ *
380
+ * return (
381
+ * <button onClick={() => addMutation.mutate('Item')}>Add</button>
382
+ * )
383
+ * }
384
+ * ```
385
+ *
386
+ * @example
387
+ * Callbacks passed per call to `mutate` only fire for the last call — `mutateAsync` gives you a
388
+ * promise per call instead, so you can wait for all of them when they succeed:
389
+ * ```tsx
390
+ * import { useMutation, useQueryClient } from '@tanstack/solid-query'
391
+ *
392
+ * function AddTodos() {
393
+ * const queryClient = useQueryClient()
394
+ *
395
+ * const addMutation = useMutation(() => ({
396
+ * mutationFn: addTodo,
397
+ * onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
398
+ * }))
399
+ *
400
+ * async function handleAddAll(todos: Array<string>) {
401
+ * try {
402
+ * await Promise.all(todos.map((todo) => addMutation.mutateAsync(todo)))
403
+ * } catch (error) {
404
+ * console.error('Failed to add todos:', error)
405
+ * }
406
+ * }
407
+ *
408
+ * return (
409
+ * <button onClick={() => handleAddAll(['Todo 1', 'Todo 2', 'Todo 3'])}>
410
+ * Add all
411
+ * </button>
412
+ * )
413
+ * }
414
+ * ```
415
+ *
416
+ * @example
417
+ * If some of the mutations above can fail independently of the others, and you want to know which ones
418
+ * did — rather than losing that information the moment the first one rejects — swap `Promise.all` for
419
+ * `Promise.allSettled`:
420
+ * ```tsx
421
+ * import { useMutation, useQueryClient } from '@tanstack/solid-query'
422
+ *
423
+ * function AddTodos() {
424
+ * const queryClient = useQueryClient()
425
+ *
426
+ * const addMutation = useMutation(() => ({
427
+ * mutationFn: addTodo,
428
+ * onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
429
+ * }))
430
+ *
431
+ * async function handleAddAll(todos: Array<string>) {
432
+ * const addResults = await Promise.allSettled(
433
+ * todos.map((todo) => addMutation.mutateAsync(todo)),
434
+ * )
435
+ *
436
+ * addResults.forEach((addResult, index) => {
437
+ * if (addResult.status === 'rejected') {
438
+ * console.error(`Failed to add "${todos[index]}":`, addResult.reason)
439
+ * }
440
+ * })
441
+ * }
442
+ *
443
+ * return (
444
+ * <button onClick={() => handleAddAll(['Todo 1', 'Todo 2', 'Todo 3'])}>
445
+ * Add all
446
+ * </button>
447
+ * )
448
+ * }
449
+ * ```
450
+ */
251
451
  function useMutation(options, queryClient) {
252
452
  const resolveClient = useQueryClientResolver(queryClient);
253
453
  const client = (0, solid_js.createMemo)(() => resolveClient());
@@ -278,6 +478,93 @@ function useMutation(options, queryClient) {
278
478
  }
279
479
  //#endregion
280
480
  //#region src/useQueries.ts
481
+ /**
482
+ * The `useQueries` hook can be used to fetch a variable number of queries.
483
+ *
484
+ * The `queries` key accepts an array with query option objects mostly identical to `useQuery` — see
485
+ * `placeholderData` below for the one difference. A custom `QueryClient` is supplied once, as `useQueries`'
486
+ * own top-level second argument, rather than per query.
487
+ *
488
+ * Having the same query key more than once in the array of query objects may cause some data to be shared
489
+ * between queries. To avoid this, consider de-duplicating the queries and map the results back to the desired
490
+ * structure.
491
+ *
492
+ * The `combine` option can be used to combine the results of the queries into a single value. The result will
493
+ * be structurally shared to be as referentially stable as possible.
494
+ *
495
+ * `placeholderData` is supported here too, but unlike `useQuery`, it doesn't receive information from
496
+ * previously rendered queries, because the number of queries can differ between renders.
497
+ * @param queriesOptions - An accessor returning the `queries` array to run, and an optional `combine`
498
+ * function.
499
+ * @param queryClient - An accessor for a custom `QueryClient`. Otherwise, the one from the nearest context
500
+ * will be used.
501
+ * @returns The combined result. Without `combine`, this is an array with all the query results, in the same
502
+ * order as the input. When `combine` is provided, this is the value returned by `combine` instead.
503
+ *
504
+ * @example
505
+ * ```tsx
506
+ * import { For } from 'solid-js'
507
+ * import { useQueries } from '@tanstack/solid-query'
508
+ *
509
+ * function Posts(props: { ids: Array<number> }) {
510
+ * const postQueries = useQueries(() => ({
511
+ * queries: props.ids.map((id) => ({
512
+ * queryKey: ['post', id],
513
+ * queryFn: () => fetchPost(id),
514
+ * staleTime: Infinity,
515
+ * })),
516
+ * }))
517
+ *
518
+ * return (
519
+ * <ul>
520
+ * <For each={postQueries}>
521
+ * {(postQuery) => {
522
+ * if (postQuery.isPending) return <li>Loading...</li>
523
+ * if (postQuery.isError) return <li>Error: {postQuery.error.message}</li>
524
+ * return <li>{postQuery.data.title}</li>
525
+ * }}
526
+ * </For>
527
+ * </ul>
528
+ * )
529
+ * }
530
+ * ```
531
+ *
532
+ * @example
533
+ * Combining results into a single value:
534
+ * ```tsx
535
+ * import { For, Match, Switch } from 'solid-js'
536
+ * import { useQueries } from '@tanstack/solid-query'
537
+ *
538
+ * function Posts(props: { ids: Array<number> }) {
539
+ * const combinedPostsQuery = useQueries(() => ({
540
+ * queries: props.ids.map((id) => ({
541
+ * queryKey: ['post', id],
542
+ * queryFn: () => fetchPost(id),
543
+ * })),
544
+ * combine: (postQueries) => {
545
+ * return {
546
+ * data: postQueries.map((postQuery) => postQuery.data),
547
+ * isPending: postQueries.some((postQuery) => postQuery.isPending),
548
+ * isError: postQueries.some((postQuery) => postQuery.isError),
549
+ * }
550
+ * },
551
+ * }))
552
+ *
553
+ * return (
554
+ * <Switch
555
+ * fallback={
556
+ * <ul>
557
+ * <For each={combinedPostsQuery.data}>{(post) => <li>{post?.title}</li>}</For>
558
+ * </ul>
559
+ * }
560
+ * >
561
+ * <Match when={combinedPostsQuery.isPending}>Loading...</Match>
562
+ * <Match when={combinedPostsQuery.isError}>Error loading posts</Match>
563
+ * </Switch>
564
+ * )
565
+ * }
566
+ * ```
567
+ */
281
568
  function useQueries(queriesOptions, queryClient) {
282
569
  const resolveClient = useQueryClientResolver(queryClient);
283
570
  const client = (0, solid_js.createMemo)(() => resolveClient());
@@ -349,6 +636,10 @@ function useQueries(queriesOptions, queryClient) {
349
636
  }
350
637
  //#endregion
351
638
  //#region src/QueryClient.ts
639
+ /**
640
+ * The core `@tanstack/query-core` `QueryClient`, typed so its `defaultOptions.queries` accepts Solid's
641
+ * `reconcile` option.
642
+ */
352
643
  var QueryClient = class extends _tanstack_query_core.QueryClient {
353
644
  constructor(config = {}) {
354
645
  super(config);
@@ -361,6 +652,28 @@ function queryOptions(options) {
361
652
  }
362
653
  //#endregion
363
654
  //#region src/useIsFetching.ts
655
+ /**
656
+ * The `useIsFetching` hook returns the `number` of the queries that your application is loading or fetching
657
+ * in the background (useful for app-wide loading indicators).
658
+ *
659
+ * @param filters - An accessor returning the {@link QueryFilters} to narrow down the matched queries.
660
+ * @param queryClient - An accessor for a custom `QueryClient`. Otherwise, the one from the nearest context
661
+ * will be used.
662
+ * @returns An accessor for the `number` of the queries that your application is currently loading or fetching
663
+ * in the background.
664
+ *
665
+ * @example
666
+ * ```tsx
667
+ * import { useIsFetching } from '@tanstack/solid-query'
668
+ *
669
+ * function GlobalLoadingIndicator() {
670
+ * // How many queries matching the posts prefix are fetching?
671
+ * const isFetchingPosts = useIsFetching(() => ({ queryKey: ['posts'] }))
672
+ *
673
+ * return isFetchingPosts() > 0 ? <span>Loading posts...</span> : null
674
+ * }
675
+ * ```
676
+ */
364
677
  function useIsFetching(filters, queryClient) {
365
678
  const resolveClient = useQueryClientResolver(queryClient);
366
679
  const client = (0, solid_js.createMemo)(() => resolveClient());
@@ -387,6 +700,27 @@ function mutationOptions(options) {
387
700
  }
388
701
  //#endregion
389
702
  //#region src/useIsMutating.ts
703
+ /**
704
+ * The `useIsMutating` hook returns the `number` of mutations that your application currently has `pending`
705
+ * (useful for app-wide loading indicators).
706
+ *
707
+ * @param filters - An accessor returning the {@link MutationFilters} to narrow down the matched mutations.
708
+ * @param queryClient - An accessor for a custom `QueryClient`. Otherwise, the one from the nearest context
709
+ * will be used.
710
+ * @returns An accessor for the `number` of the mutations that your application currently has `pending`.
711
+ *
712
+ * @example
713
+ * ```tsx
714
+ * import { useIsMutating } from '@tanstack/solid-query'
715
+ *
716
+ * function PostsMutatingIndicator() {
717
+ * // How many mutations matching the posts prefix are in progress?
718
+ * const isMutatingPosts = useIsMutating(() => ({ mutationKey: ['posts'] }))
719
+ *
720
+ * return isMutatingPosts() > 0 ? <span>Saving posts...</span> : null
721
+ * }
722
+ * ```
723
+ */
390
724
  function useIsMutating(filters, queryClient) {
391
725
  const resolveClient = useQueryClientResolver(queryClient);
392
726
  const client = (0, solid_js.createMemo)(() => resolveClient());
@@ -406,6 +740,79 @@ function useIsMutating(filters, queryClient) {
406
740
  function getResult(mutationCache, options) {
407
741
  return mutationCache.findAll(options.filters).map((mutation) => options.select ? options.select(mutation) : mutation.state);
408
742
  }
743
+ /**
744
+ * `useMutationState` is a hook that gives you access to all mutations in the `MutationCache`. You can pass
745
+ * `filters` ({@link MutationFilters}) to narrow down your mutations, and `select` to transform the mutation
746
+ * state.
747
+ *
748
+ * @param options - An accessor returning the `filters` to narrow down matched mutations, and an optional
749
+ * `select` to transform the mutation state.
750
+ * @param queryClient - An accessor for a custom `QueryClient`. Otherwise, the one from the nearest context
751
+ * will be used.
752
+ * @returns An accessor for an array of whatever `select` returns for each matching mutation.
753
+ *
754
+ * @example
755
+ * Get all variables of all running mutations:
756
+ * ```tsx
757
+ * import { useMutationState } from '@tanstack/solid-query'
758
+ *
759
+ * function PendingPosts() {
760
+ * const pendingVariables = useMutationState(() => ({
761
+ * filters: { status: 'pending' },
762
+ * select: (mutation) => mutation.state.variables,
763
+ * }))
764
+ *
765
+ * return <>{pendingVariables().length} posts saving...</>
766
+ * }
767
+ * ```
768
+ *
769
+ * @example
770
+ * Get all data for specific mutations via the `mutationKey`:
771
+ * ```tsx
772
+ * import { useMutation, useMutationState } from '@tanstack/solid-query'
773
+ *
774
+ * const mutationKey = ['posts']
775
+ *
776
+ * function Posts() {
777
+ * // Some mutation that we want to get the state for
778
+ * const createPostsMutation = useMutation(() => ({
779
+ * mutationKey,
780
+ * mutationFn: createPosts,
781
+ * }))
782
+ *
783
+ * const savedPosts = useMutationState(() => ({
784
+ * // this mutation key needs to match the mutation key of the given mutation (see above)
785
+ * filters: { mutationKey, status: 'success' },
786
+ * select: (mutation) => mutation.state.data,
787
+ * }))
788
+ *
789
+ * return (
790
+ * <button onClick={() => createPostsMutation.mutate(['New Post'])}>
791
+ * Create post ({savedPosts().length} saved so far)
792
+ * </button>
793
+ * )
794
+ * }
795
+ * ```
796
+ *
797
+ * @example
798
+ * Access the latest successful mutation data via the `mutationKey`. Each invocation of `mutate` adds a new
799
+ * entry to the mutation cache for `gcTime` milliseconds — with the `status: 'success'` filter below, check the
800
+ * last item that `useMutationState` returns to get the latest successful invocation:
801
+ * ```tsx
802
+ * import { useMutationState } from '@tanstack/solid-query'
803
+ *
804
+ * function LatestPost() {
805
+ * const savedPosts = useMutationState(() => ({
806
+ * filters: { mutationKey: ['posts'], status: 'success' },
807
+ * select: (mutation) => mutation.state.data,
808
+ * }))
809
+ *
810
+ * const latestPost = () => savedPosts()[savedPosts().length - 1]
811
+ *
812
+ * return <span>{latestPost()?.title}</span>
813
+ * }
814
+ * ```
815
+ */
409
816
  function useMutationState(options = () => ({}), queryClient) {
410
817
  const resolveClient = useQueryClientResolver(queryClient);
411
818
  const client = (0, solid_js.createMemo)(() => resolveClient());