I am just curious to know the way to populate extra
and extraOptions
, and from where the arguments must be passed in order so that they can get populated and can be used then in creating some condition based scenario. Well queryFn
itself is used for creating custom query function in the Redux-Toolkit (RTK) query (RTKQ).
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
const shiprocketApiSlice = createApi({
baseQuery: fetchBaseQuery({
baseUrl: "https://apiv2.shiprocket.in/v1/external",
prepareHeaders: (headers, { getState, extra, type, endpoint }) => {
const token =
"...someToken";
token && headers.set("authorization", `Bearer ${token}`);
console.log(
"the extra value of the ====> ",
extra,
getState(),
type,
endpoint,
headers
);
return headers;
},
}),
endpoints: (builder) => ({
updateUser: builder.mutation({
query: (user) => {
return {
url: `/users/${user.queryArg}`,
headers: {
"X-Scope": "1234567890",
},
};
},
}),
createOrderShiprocket: builder.mutation({
queryFn: async (args, api, extraOptions, baseQuery) => {
console.log(
"printin all the agrs of the qrfn to see what exactly it is ===> ",
args,
api,
"extraoptions==>",
extraOptions,
"base==>",
baseQuery
);
const response = await baseQuery(args, api, extraOptions);
console.log("the response ==>", response);
return { error: { message: "error occured" } };
},
}),
}),
});
export const { useCreateOrderShiprocketMutation, useUpdateUserMutation } =
shiprocketApiSlice;
I have used the hooks in this file
"use client";
import React from "react";
import {
useCreateOrderShiprocketMutation,
useUpdateUserMutation,
} from "@/store/features/shiprocket/shiprocketApiSlice";
const TestFolderPage = () => {
const [createOrderShiprocket, { data: TheOrderList }] =
useCreateOrderShiprocketMutation();
const [updateUser, { data: updatedData }] = useUpdateUserMutation();
const handleClick = () => {
console.log("the click");
updateUser({ queryArg: 12344 });
createOrderShiprocket({ userId: 123 });
};
return <div onClick={handleClick}>TestFolderPage</div>;
};
export default TestFolderPage;
What is the use of
extra
andextraOptions
in Redux-Toolkit (RTK) query (RTKQ)?
extra
Provided as thunk.extraArgument
to the configureStore getDefaultMiddleware option.
export interface BaseQueryApi {
signal: AbortSignal
abort: (reason?: string) => void
dispatch: ThunkDispatch<any, any, any>
getState: () => unknown
extra: unknown // <-- specified thunk.extraArgument
endpoint: string
type: 'query' | 'mutation'
forced?: boolean
}
extra
is the extra argument used with Redux-Toolkit's Thunk middleware when configuring the Redux store. See Customizing the included Middleware for details. The basic example is a follows:
import { configureStore } from '@reduxjs/toolkit';
const store = configureStore({
reducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
thunk: {
extraArgument: /* whatever value you need here */,
},
}),
});
This extraArgument
is exposed out in the thunkApi
of createAsyncThunk
actions, and apparently as part of the Redux-Toolkit Query's prepareHeaders
function signature.
type prepareHeaders = (
headers: Headers,
api: {
getState: () => unknown
extra: unknown // <-- the extra arg from store
endpoint: string
type: 'query' | 'mutation'
forced: boolean | undefined
}
) => Headers | void
extraOptions
See extraOptions
in the docs:
Quite simply, extraOptions
is an optional object that is passed as the third argument to the supplied baseQuery
function, e.g. the base query function returned by fetchBaseQuery
in your code example. See fetchBaseQuery
signature.
type FetchBaseQuery = (
args: FetchBaseQueryArgs
) => (
args: string | FetchArgs,
api: BaseQueryApi,
extraOptions: ExtraOptions // <-- third arg, the extra options
) => FetchBaseQueryResult
How could be populate them when using the
query
&queryFn
?
I've already covered above where and how to specify/add the extra
value when configuring the store. The extraOptions
can specified per endpoint.
Example:
updateUser: builder.mutation({
query: (user) => ({
url: `/users/${user.queryArg}`,
headers: {
'X-Scope': '1234567890',
},
}),
extraOptions: {
// any custom extra options/properties you want to pass to the base query
},
}),
createOrderShiprocket: builder.mutation({
queryFn: async (args, api, extraOptions, baseQuery) => { // <-- accessed here
...
const response = await baseQuery(args, api, extraOptions); // <-- passed through
...
},
extraOptions: {
// any custom extra options/properties you want to pass to the base query
},
}),
This alone isn't particularly useful until you have the need to customize your base query function. See Customizing Queries.
For example, a fairly trivial customization is to add automatic retries for failed queries.
import { createApi, fetchBaseQuery, retry } from '@reduxjs/toolkit/query/react';
const baseQuery = retry(
fetchBaseQuery({
baseUrl: "https://apiv2.shiprocket.in/v1/external",
prepareHeaders: (headers, { getState, extra, type, endpoint }) => {
const token = "...someToken";
token && headers.set("authorization", `Bearer ${token}`);
return headers;
},
}),
{
maxRetries: 5,
},
);
const shiprocketApiSlice = createApi({
baseQuery, // <-- 5 retries by default
endpoints: (builder) => ({
updateUser: builder.mutation({
query: (user) => ({
url: `/users/${user.queryArg}`,
headers: {
'X-Scope': '1234567890',
},
}),
}),
createOrderShiprocket: builder.mutation({
queryFn: async (args, api, extraOptions, baseQuery) => {
...
const response = await baseQuery(args, api, extraOptions);
...
},
extraOptions: {
maxRetries: 8 // <-- override default 5
},
}),
}),
});
It's really up to you and your app's specific use cases and needs what extra
and extraOptions
are relevant and/or helpful.