deno.land / x / jotai@v1.8.4 / docs / integrations / query.mdx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
---title: Querydescription: This doc describes `jotai/query` bundle.nav: 4.03---
This is the Jotai integration with [TanStack Query v4](https://tanstack.com/query/v4), a set of hooks and tools for managing async state (typically external data).
From the [Overview docs](https://tanstack.com/query/v4/docs/overview):
> React Query is often described as the missing data-fetching library for React, but in more technical terms, it makes **fetching, caching, synchronizing and updating server state** in your React applications a breeze.Jotai with TanStack Query provides a wonderful interface with all of the TanStack Query features, providing you the ability to use those features in combination with your existing Jotai state.
## Install
In addition to `jotai`, you have to install `@tanstack/query-core` to make use of this bundle and its functions.
```bashyarn add @tanstack/query-core```
## atomWithQuery
`atomWithQuery` creates a new atom that implements a standard [`Query`](https://tanstack.com/query/v4/docs/guides/queries) from TanStack Query. This function combines both Jotai `atom` features and `useQuery` features in a single atom. This atom supports all features you'd expect to find when using the standard `@tanstack/react-query` package.
> A query is a declarative dependency on an asynchronous source of data that is tied to a unique key. A query can be used with any Promise based method (including GET and POST methods) to fetch data from a server.```jsximport { useAtom } from 'jotai'import { atomWithQuery } from 'jotai/query'
const idAtom = atom(1)const userAtom = atomWithQuery((get) => ({ queryKey: ['users', get(idAtom)], queryFn: async ({ queryKey: [, id] }) => { const res = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`) return res.json() },}))
const UserData = () => { const [data] = useAtom(userAtom) return <div>{JSON.stringify(data)}</div>}```
## atomWithInfiniteQuery
`atomWithInfiniteQuery` is very similar to `atomWithQuery`, however it creates an `InfiniteQuery`, which is used for data that is meant to be paginated. You can [read more about Infinite Queries here](https://tanstack.com/query/v4/docs/guides/infinite-queries). This atom supports all features you'd expect to find when using the standard `@tanstack/react-query` package.
> Rendering lists that can additively "load more" data onto an existing set of data or "infinite scroll" is also a very common UI pattern. React Query supports a useful version of useQuery called useInfiniteQuery for querying these types of lists.A notable difference between a standard query atom is the additional option `getNextPageParam` and `getPreviousPageParam`, which is what you'll use to instruct the query on how to fetch any additional pages.
```jsximport { useAtom } from 'jotai'import { atomWithInfiniteQuery } from 'jotai/query'
const idAtom = atom(1)const userAtom = atomWithInfiniteQuery((get) => ({ queryKey: ['users', get(idAtom)], queryFn: async ({ queryKey: [, id] }) => { const res = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`) return res.json() }, // infinite queries can support paginated fetching getNextPageParam: (lastPage, pages) => lastPage.nextCursor,}))
const UserData = () => { const [data] = useAtom(userAtom) return data.pages.map((userData, index) => ( <div key={index}>{JSON.stringify(userData)}</div> ))}```
### Fetching pages and refetching
Using the same atom as in the above example, we can use the `update` method returned from `useAtom` to call different `@tanstack/react-query` methods:
```jsconst UserData = () => { const [data, update] = useAtom(userAtom) const handleFetchNextPage = () => update({ type: 'fetchNextPage' }) const handleFetchPreviousPage = () => update({ type: 'fetchPreviousPage' }) const handleRefetchAllPages = () => update({ type: 'refetch' })}```
## Referencing the same instance of Query Client in your project
Perhaps you have some custom hooks in your project that utilises the `useQueryClient()` hook to obtain the `QueryClient` object and call its methods.
To ensure that you reference the same `QueryClient` object, be sure to wrap the root of your project in a `<Provider>` and initialise `queryClientAtom` with the same `queryClient` value you provided to `QueryClientProvider`.
Without this step, `useQueryAtom` will reference a seperate `QueryClient` from any hooks that utilise the `useQueryClient()` hook to get the queryClient.
### Example
In the example below, we have a mutation hook, `useTodoMutation` and a query `todosAtom`.
We included an initialisation step in our root `<App>` node.
Although they reference methods same query key (`'todos'`), the `onSuccess` invalidation in `useTodoMutation` will not trigger **if the `Provider` initialisation step was not done.**
This will result in `todosAtom` showing stale data as it was not prompted to refetch.
```jsximport { useMutation, useQueryClient, QueryClient, QueryClientProvider,} from '@tanstack/react-query'import { atomWithQuery, queryClientAtom } from 'jotai/query'
const queryClient = new QueryClient()export const App = () => { return ( <QueryClientProvider client={queryClient}> {/* This Provider initalization step is needed so that we reference the same queryClient in both atomWithQuery and other parts of the app. Without this, our useQueryClient() hook will return a different QueryClient object */} <Provider initialValues={[[queryClientAtom, queryClient]]}> <App /> </Provider> </QueryClientProvider> )}
export const todosAtom = atomWithQuery((get) => { return { queryKey: ['todos'], queryFn: () => fetch('/todos'), }})
export const useTodoMutation = () => { const queryClient = useQueryClient() return useMutation( async (body: todo) => { await fetch('/todo', { Method: 'POST', Body: body }) }, { onSuccess: () => { void queryClient.invalidateQueries(['todos']) }, onError, } )}```
## SSR support
Both 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/v4/docs/guides/ssr) that React Query supports for use within SSR apps, [hydration](https://tanstack.com/query/v4/docs/guides/ssr#using-hydration) or [`initialData`](https://tanstack.com/query/v4/docs/guides/ssr#using-initialdata).
## Error handling
Fetch error will be thrown and can be caught with ErrorBoundary.Refetching may recover from a temporary error.
See [a working example](https://codesandbox.io/s/04mepx) to learn more.
## Examples
### Basic demo
<CodeSandbox id="ij2sd" />### Hackernews
<CodeSandbox id="u4sli" />
jotai

Version Info

Tagged at
a year ago