skip to Main Content

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;

2

Answers


  1. Modifying fetchBaseQuery to Use extra:

    Currently, the extra parameter in prepareHeaders isn’t being utilized because it’s not set anywhere. If you want to use this, you need to provide a value for extra when calling fetchBaseQuery. However, typically extra is used for more advanced scenarios, like when you have a middleware setting it.

    Passing and Using extraOptions in queryFn:

    To demonstrate how to pass and use extraOptions, I’ll modify the createOrderShiprocket mutation’s usage in your component.

    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) => ({
            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
            );
    
            // Use extraOptions here for conditional logic
            if (extraOptions.someCondition) {
              // Custom handling based on extraOptions
            }
    
            const response = await baseQuery(args, api, extraOptions);
            console.log('the response ==>', response);
            return { error: { message: 'error occured' } };
          },
        }),
      }),
    });
    
    export const { useCreateOrderShiprocketMutation, useUpdateUserMutation } = shiprocketApiSlice;
    

    And then:

    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, extraOption: 'someValue' }); // Passing extraOption here
      };
    
      return <div onClick={handleClick}>TestFolderPage</div>;
    };
    
    export default TestFolderPage;
    
    Login or Signup to reply.
  2. What is the use of extra and extraOptions in Redux-Toolkit (RTK) query (RTKQ)?

    extra

    Provided as thunk.extraArgument to the configureStore getDefaultMiddleware option.

    BaseQueryApi

    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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search