Skip to content

Commit 6cf605f

Browse files
committed
📝 Extend onQueryStarted documentation
* add explicit query lifecycle example * add hover tooltips + example for `onQueryStarted` * increase consistency of fake example endpoints
1 parent cb3eaf2 commit 6cf605f

File tree

8 files changed

+136
-10
lines changed

8 files changed

+136
-10
lines changed

docs/rtk-query/api/createApi.mdx

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,46 @@ async function onQueryStarted(
484484
): Promise<void>
485485
```
486486

487+
```ts title="onQueryStarted query lifecycle example"
488+
// file: notificationsSlice.ts noEmit
489+
export const messageCreated = (msg: string) => ({
490+
type: 'notifications/messageCreated',
491+
payload: msg,
492+
})
493+
494+
// file: api.ts
495+
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'
496+
import { messageCreated } from './notificationsSlice'
497+
498+
export interface Post {
499+
id: number
500+
name: string
501+
}
502+
503+
const api = createApi({
504+
baseQuery: fetchBaseQuery({
505+
baseUrl: '/',
506+
}),
507+
endpoints: (build) => ({
508+
getPost: build.query<Post, number>({
509+
query: (id) => `posts/${id}`,
510+
async onQueryStarted(id, { dispatch, queryFulfilled }) {
511+
// `onStart` side-effect
512+
dispatch(messageCreated('Fetching posts...'))
513+
try {
514+
const { data } = await queryFulfilled
515+
// `onSuccess` side-effect
516+
dispatch(messageCreated('Posts received!'))
517+
} catch (err) {
518+
// `onError` side-effect
519+
dispatch(messageCreated('Error fetching posts!'))
520+
}
521+
},
522+
}),
523+
}),
524+
})
525+
```
526+
487527
### `onCacheEntryAdded`
488528

489529
_(optional)_

docs/rtk-query/usage/automated-refetching.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -797,7 +797,7 @@ const api = createApi({
797797
tagTypes: ['Post', 'UNAUTHORIZED', 'UNKNOWN_ERROR'],
798798
endpoints: (build) => ({
799799
postById: build.query<Post, number>({
800-
query: (id) => `post/${id}`,
800+
query: (id) => `posts/${id}`,
801801
providesTags: (result, error, id) =>
802802
result
803803
? [{ type: 'Post', id }]

docs/rtk-query/usage/mutations.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ const api = createApi({
3636
// highlight-start
3737
// note: an optional `queryFn` may be used in place of `query`
3838
query: ({ id, ...patch }) => ({
39-
url: `post/${id}`,
39+
url: `posts/${id}`,
4040
method: 'PATCH',
4141
body: patch,
4242
}),

docs/rtk-query/usage/optimistic-updates.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,12 @@ const api = createApi({
3535
tagTypes: ['Post'],
3636
endpoints: (build) => ({
3737
getPost: build.query<Post, number>({
38-
query: (id) => `post/${id}`,
38+
query: (id) => `posts/${id}`,
3939
providesTags: ['Post'],
4040
}),
4141
updatePost: build.mutation<void, Pick<Post, 'id'> & Partial<Post>>({
4242
query: ({ id, ...patch }) => ({
43-
url: `post/${id}`,
43+
url: `posts/${id}`,
4444
method: 'PATCH',
4545
body: patch,
4646
}),
@@ -64,7 +64,7 @@ const api = createApi({
6464
})
6565
```
6666

67-
or, if you prefer the slighty shorter version with `.catch`
67+
or, if you prefer the slightly shorter version with `.catch`
6868

6969
```diff
7070
- async onQueryStarted({ id, ...patch }, { dispatch, queryFulfilled }) {

docs/rtk-query/usage/queries.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ const api = createApi({
3838
getPost: build.query<Post, number>({
3939
// highlight-start
4040
// note: an optional `queryFn` may be used in place of `query`
41-
query: (id) => ({ url: `post/${id}` }),
41+
query: (id) => ({ url: `posts/${id}` }),
4242
// Pick out data and prevent nested properties in a hook or selector
4343
transformResponse: (response: { data: Post }) => response.data,
4444
providesTags: (result, error, id) => [{ type: 'Post', id }],

src/query/core/buildMiddleware/queryLifecycle.ts

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,44 @@ declare module '../../endpointDefinitions' {
7373
BaseQuery extends BaseQueryFn,
7474
ReducerPath extends string = string
7575
> {
76+
/**
77+
* A function that is called when the individual query is started. The function is called with a lifecycle api object containing properties such as `queryFulfilled`, allowing code to be run when a query is started, when it succeeds, and when it fails (i.e. throughout the lifecycle of an individual query/mutation call).
78+
*
79+
* Can be used to perform side-effects throughout the lifecycle of the query.
80+
*
81+
* @example
82+
* ```ts
83+
* import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'
84+
* import { messageCreated } from './notificationsSlice
85+
* export interface Post {
86+
* id: number
87+
* name: string
88+
* }
89+
*
90+
* const api = createApi({
91+
* baseQuery: fetchBaseQuery({
92+
* baseUrl: '/',
93+
* }),
94+
* endpoints: (build) => ({
95+
* getPost: build.query<Post, number>({
96+
* query: (id) => `posts/${id}`,
97+
* async onQueryStarted(id, { dispatch, queryFulfilled }) {
98+
* // `onStart` side-effect
99+
* dispatch(messageCreated('Fetching posts...'))
100+
* try {
101+
* const { data } = await queryFulfilled
102+
* // `onSuccess` side-effect
103+
* dispatch(messageCreated('Posts received!'))
104+
* } catch (err) {
105+
* // `onError` side-effect
106+
* dispatch(messageCreated('Error fetching posts!'))
107+
* }
108+
* }
109+
* }),
110+
* }),
111+
* })
112+
* ```
113+
*/
76114
onQueryStarted?(
77115
arg: QueryArg,
78116
api: QueryLifecycleApi<QueryArg, BaseQuery, ResultType, ReducerPath>
@@ -86,6 +124,54 @@ declare module '../../endpointDefinitions' {
86124
BaseQuery extends BaseQueryFn,
87125
ReducerPath extends string = string
88126
> {
127+
/**
128+
* A function that is called when the individual mutation is started. The function is called with a lifecycle api object containing properties such as `queryFulfilled`, allowing code to be run when a query is started, when it succeeds, and when it fails (i.e. throughout the lifecycle of an individual query/mutation call).
129+
*
130+
* Can be used for `optimistic updates`.
131+
*
132+
* @example
133+
*
134+
* ```ts
135+
* import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'
136+
* export interface Post {
137+
* id: number
138+
* name: string
139+
* }
140+
*
141+
* const api = createApi({
142+
* baseQuery: fetchBaseQuery({
143+
* baseUrl: '/',
144+
* }),
145+
* tagTypes: ['Post'],
146+
* endpoints: (build) => ({
147+
* getPost: build.query<Post, number>({
148+
* query: (id) => `posts/${id}`,
149+
* providesTags: ['Post'],
150+
* }),
151+
* updatePost: build.mutation<void, Pick<Post, 'id'> & Partial<Post>>({
152+
* query: ({ id, ...patch }) => ({
153+
* url: `posts/${id}`,
154+
* method: 'PATCH',
155+
* body: patch,
156+
* }),
157+
* invalidatesTags: ['Post'],
158+
* async onQueryStarted({ id, ...patch }, { dispatch, queryFulfilled }) {
159+
* const patchResult = dispatch(
160+
* api.util.updateQueryData('getPost', id, (draft) => {
161+
* Object.assign(draft, patch)
162+
* })
163+
* )
164+
* try {
165+
* await queryFulfilled
166+
* } catch {
167+
* patchResult.undo()
168+
* }
169+
* },
170+
* }),
171+
* }),
172+
* })
173+
* ```
174+
*/
89175
onQueryStarted?(
90176
arg: QueryArg,
91177
api: MutationLifecycleApi<QueryArg, BaseQuery, ResultType, ReducerPath>

src/query/endpointDefinitions.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ export type EndpointBuilder<
368368
* baseQuery,
369369
* endpoints: (build) => ({
370370
* getPost: build.query({
371-
* query: (id) => ({ url: `post/${id}` }),
371+
* query: (id) => ({ url: `posts/${id}` }),
372372
* // Pick out data and prevent nested properties in a hook or selector
373373
* transformResponse: (response) => response.data,
374374
* // `result` is the server response
@@ -398,7 +398,7 @@ export type EndpointBuilder<
398398
* baseQuery,
399399
* endpoints: (build) => ({
400400
* updatePost: build.mutation({
401-
* query: ({ id, ...patch }) => ({ url: `post/${id}`, method: 'PATCH', body: patch }),
401+
* query: ({ id, ...patch }) => ({ url: `posts/${id}`, method: 'PATCH', body: patch }),
402402
* // Pick out data and prevent nested properties in a hook or selector
403403
* transformResponse: (response) => response.data,
404404
* // `result` is the server response

src/query/tests/optimisticUpdates.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@ const api = createApi({
2121
tagTypes: ['Post'],
2222
endpoints: (build) => ({
2323
post: build.query<Post, string>({
24-
query: (id) => `post/${id}`,
24+
query: (id) => `posts/${id}`,
2525
providesTags: ['Post'],
2626
}),
2727
updatePost: build.mutation<void, Pick<Post, 'id'> & Partial<Post>>({
2828
query: ({ id, ...patch }) => ({
29-
url: `post/${id}`,
29+
url: `posts/${id}`,
3030
method: 'PATCH',
3131
body: patch,
3232
}),

0 commit comments

Comments
 (0)