Skip to content

Commit df14c08

Browse files
feat: QueryClientAtomProvider (#133)
1 parent 6883383 commit df14c08

File tree

11 files changed

+193
-119
lines changed

11 files changed

+193
-119
lines changed

README.md

Lines changed: 98 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66

77
- [Support](#support)
88
- [Install](#install)
9+
- [Usage](#usage)
910
- [Incremental Adoption](#incremental-adoption)
11+
- [Exported Provider](#exported-provider)
1012
- [Exported Functions](#exported-functions)
1113
- [atomWithQuery](#atomwithquery-usage)
1214
- [atomWithQueries](#atomwithqueries-usage)
@@ -16,7 +18,6 @@
1618
- [Suspense](#suspense)
1719
- [atomWithSuspenseQuery](#atomwithsuspensequery-usage)
1820
- [atomWithSuspenseInfiniteQuery](#atomwithsuspenseinfinitequery-usage)
19-
- [QueryClient Instance](#referencing-the-same-instance-of-query-client)
2021
- [SSR Support](#ssr-support)
2122
- [Error Handling](#error-handling)
2223
- [Dev Tools](#devtools)
@@ -25,19 +26,50 @@
2526

2627
### Support
2728

28-
jotai-tanstack-query currently supports TanStack Query v5.
29+
jotai-tanstack-query currently supports [Jotai v2](https://jotai.org) and [TanStack Query v5](https://tanstack.com/query/v5).
2930

3031
### Install
3132

32-
In addition to `jotai`, you have to install `jotai-tanstack-query` and `@tanstack/query-core` to use the extension.
33-
3433
```bash
35-
npm i jotai-tanstack-query @tanstack/query-core
34+
npm i jotai jotai-tanstack-query @tanstack/react-query
35+
```
36+
37+
### Usage
38+
39+
```jsx
40+
import { QueryClient } from '@tanstack/react-query'
41+
import { useAtom } from 'jotai'
42+
import { atomWithQuery } from 'jotai-tanstack-query'
43+
import { QueryClientAtomProvider } from 'jotai-tanstack-query/react'
44+
45+
const queryClient = new QueryClient()
46+
47+
export const Root = () => {
48+
return (
49+
<QueryClientAtomProvider client={queryClient}>
50+
<App />
51+
</QueryClientAtomProvider>
52+
)
53+
}
54+
55+
const todosAtom = atomWithQuery(() => ({
56+
queryKey: ['todos'],
57+
queryFn: fetchTodoList,
58+
}))
59+
60+
const App = () => {
61+
const [{ data, isPending, isError }] = useAtom(todosAtom)
62+
63+
if (isPending) return <div>Loading...</div>
64+
if (isError) return <div>Error</div>
65+
66+
return <div>{JSON.stringify(data)}</div>
67+
}
3668
```
3769

3870
### Incremental Adoption
3971

40-
You can incrementally adopt `jotai-tanstack-query` in your app. It's not an all or nothing solution. You just have to ensure you are using the same QueryClient instance. [same QueryClient](#referencing-the-same-instance-of-query-client).
72+
You can incrementally adopt `jotai-tanstack-query` in your app. It's not an all or nothing solution. You just have to ensure you are using the [same QueryClient instance](#exported-provider).
4173

4274
```jsx
4375
// existing useQueryHook
@@ -54,6 +86,59 @@ const todosAtom = atomWithQuery(() => ({
5486
const [{ data, isPending, isError }] = useAtom(todosAtom)
5587
```
5688

89+
### Exported provider
90+
91+
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/jotaijs/jotai-tanstack-query/tree/main/examples/08_query_client_atom_provider)
92+
93+
`QueryClientAtomProvider` is a ready-to-use wrapper that combines Jotai Provider and TanStack Query QueryClientProvider.
94+
95+
```jsx
96+
import { QueryClient } from '@tanstack/react-query'
97+
import { QueryClientAtomProvider } from 'jotai-tanstack-query/react'
98+
99+
const queryClient = new QueryClient()
100+
101+
export const Root = () => {
102+
return (
103+
<QueryClientAtomProvider client={queryClient}>
104+
<App />
105+
</QueryClientAtomProvider>
106+
)
107+
}
108+
```
109+
110+
Yes, you can absolutely combine them yourself.
111+
112+
```diff
113+
- import { QueryClient } from '@tanstack/react-query'
114+
- import { QueryClientAtomProvider } from 'jotai-tanstack-query/react'
115+
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
116+
+ import { Provider } from 'jotai/react'
117+
+ import { useHydrateAtoms } from 'jotai/react/utils'
118+
+ import { queryClientAtom } from 'jotai-tanstack-query'
119+
120+
const queryClient = new QueryClient()
121+
122+
+ const HydrateAtoms = ({ children }) => {
123+
+ useHydrateAtoms([[queryClientAtom, queryClient]])
124+
+ return children
125+
+ }
126+
127+
export const Root = () => {
128+
return (
129+
- <QueryClientAtomProvider client={queryClient}>
130+
+ <QueryClientProvider client={queryClient}>
131+
+ <Provider>
132+
+ <HydrateAtoms>
133+
<App />
134+
+ </HydrateAtoms>
135+
+ </Provider>
136+
+ </QueryClientProvider>
137+
- </QueryClientAtomProvider>
138+
)
139+
}
140+
```
141+
57142
### Exported functions
58143

59144
- `atomWithQuery` for [useQuery](https://tanstack.com/query/v5/docs/react/reference/useQuery)
@@ -363,76 +448,6 @@ const Posts = () => {
363448
}
364449
```
365450

366-
### Referencing the same instance of Query Client
367-
368-
Perhaps you have some custom hooks in your project that utilizes the `useQueryClient()` hook to obtain the `QueryClient` object and call its methods.
369-
370-
To ensure that you reference the same `QueryClient` object, be sure to wrap the root of your project in a `<Provider>` and initialize `queryClientAtom` with the same `queryClient` value you provided to `QueryClientProvider`.
371-
372-
Without this step, `useQueryAtom` will reference a separate `QueryClient` from any hooks that utilize the `useQueryClient()` hook to get the queryClient.
373-
374-
Alternatively, you can specify your `queryClient` with `getQueryClient` parameter.
375-
376-
#### Example
377-
378-
In the example below, we have a mutation hook, `useTodoMutation` and a query `todosAtom`.
379-
380-
We included an initialization step in our root `<App>` node.
381-
382-
Although they reference methods same query key (`'todos'`), the `onSuccess` invalidation in `useTodoMutation` will not trigger **if the `Provider` initialization step was not done.**
383-
384-
This will result in `todosAtom` showing stale data as it was not prompted to refetch.
385-
386-
```jsx
387-
import { Provider } from 'jotai/react'
388-
import {
389-
useMutation,
390-
useQueryClient,
391-
QueryClient,
392-
} from '@tanstack/react-query'
393-
import { atomWithQuery, queryClientAtom } from 'jotai-tanstack-query'
394-
import { QueryClientProvider } from 'jotai-tanstack-query/react'
395-
396-
const queryClient = new QueryClient()
397-
398-
export const Root = () => {
399-
return (
400-
<QueryClientProvider client={queryClient}>
401-
<Provider>
402-
<App />
403-
</Provider>
404-
</QueryClientProvider>
405-
)
406-
}
407-
408-
export const todosAtom = atomWithQuery(
409-
(get) => {
410-
return {
411-
queryKey: ["todos"],
412-
queryFn: () => fetch("/todos"),
413-
}
414-
},
415-
() => queryClient
416-
)
417-
418-
419-
export const useTodoMutation = () => {
420-
const queryClient = useQueryClient()
421-
422-
return useMutation(
423-
async (body: todo) => {
424-
await fetch('/todo', { Method: 'POST', Body: body })
425-
},
426-
{
427-
onSuccess: () => {
428-
void queryClient.invalidateQueries(['todos'])
429-
},
430-
onError,
431-
}
432-
)
433-
}
434-
```
435-
436451
### SSR support
437452

438453
All atoms can be used within the context of a server side rendered app, such as a next.js app or Gatsby app. You can [use both options](https://tanstack.com/query/v5/docs/guides/ssr) that React Query supports for use within SSR apps, [hydration](https://tanstack.com/query/v5/docs/react/guides/ssr#using-the-hydration-apis) or [`initialData`](https://tanstack.com/query/v5/docs/react/guides/ssr#get-started-fast-with-initialdata).
@@ -452,30 +467,21 @@ In order to use the Devtools, you need to install it additionally.
452467
$ npm i @tanstack/react-query-devtools --save-dev
453468
```
454469

455-
All you have to do is put the `<ReactQueryDevtools />` within `<QueryClientProvider />`.
470+
All you have to do is put the `<ReactQueryDevtools />` within `<QueryClientAtomProvider />`.
456471

457472
```tsx
458473
import { QueryClient, QueryCache } from '@tanstack/react-query'
459474
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
460-
import { QueryClientProvider } from 'jotai-tanstack-query/react'
461-
import { queryClientAtom } from 'jotai-tanstack-query'
462-
463-
const queryClient = new QueryClient({
464-
defaultOptions: {
465-
queries: {
466-
staleTime: Infinity,
467-
},
468-
},
469-
})
475+
import { QueryClientAtomProvider } from 'jotai-tanstack-query/react'
476+
477+
const queryClient = new QueryClient()
470478

471479
export const Root = () => {
472480
return (
473-
<QueryClientProvider client={queryClient}>
474-
<Provider>
475-
<App />
476-
</Provider>
481+
<QueryClientAtomProvider client={queryClient}>
482+
<App />
477483
<ReactQueryDevtools />
478-
</QueryClientProvider>
484+
</QueryClientAtomProvider>
479485
)
480486
}
481487
```

examples/08_incremental_adoption/package.json renamed to examples/08_query_client_atom_provider/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "jotai-tanstack-query-example-incremental-adoption",
2+
"name": "jotai-tanstack-query-example-query-client-atom-provider",
33
"version": "0.1.0",
44
"private": true,
55
"dependencies": {

examples/08_incremental_adoption/src/App.tsx renamed to examples/08_query_client_atom_provider/src/App.tsx

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { QueryClient, useQuery } from '@tanstack/react-query'
2-
import { Provider, useAtom } from 'jotai/react'
2+
import { useAtom } from 'jotai/react'
33
import { atom } from 'jotai/vanilla'
44
import { atomWithQuery } from 'jotai-tanstack-query'
5-
import { QueryClientProvider } from 'jotai-tanstack-query/react'
5+
import { QueryClientAtomProvider } from 'jotai-tanstack-query/react'
66

77
const queryClient = new QueryClient()
88

@@ -85,13 +85,11 @@ const Controls = () => {
8585

8686
const App = () => (
8787
<>
88-
<QueryClientProvider client={queryClient}>
89-
<Provider>
90-
<Controls />
91-
<UserDataRawFetch />
92-
<UserData />
93-
</Provider>
94-
</QueryClientProvider>
88+
<QueryClientAtomProvider client={queryClient}>
89+
<Controls />
90+
<UserDataRawFetch />
91+
<UserData />
92+
</QueryClientAtomProvider>
9593
</>
9694
)
9795

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
"examples:05_mutation": "pnpm --filter ./examples/05_mutation run dev",
5252
"examples:06_refetch": "pnpm --filter ./examples/06_refetch run dev",
5353
"examples:07_queries": "pnpm --filter ./examples/07_queries run dev",
54-
"examples:08_incremental_adoption": "pnpm --filter ./examples/08_incremental_adoption run dev",
54+
"examples:08_query_client_atom_provider": "pnpm --filter ./examples/08_query_client_atom_provider run dev",
5555
"examples:09_error_boundary": "pnpm --filter ./examples/09_error_boundary run dev"
5656
},
5757
"keywords": [

0 commit comments

Comments
 (0)