Search code examples
reduxrtk-query

RTK Query. How to handle path variable in baseUrl?


I need to make a request to a URL like this /common/path/:userId/specific/path/endpoints. /common/path is shared across many endpoints, and I don't want to put all of those queries in the same file. Ideally, I'd create a slice for /common/path/:userId/specific/path and its endpoints. I have userId when the store is created. Could I pass userId into the slice and put it in the baseUrl somehow?

Or am I approaching this wrong? Is there a better way? I can't change the structure of the URL.

EDIT: This is what I'm trying.

In MyFile.jsx

const store = configureStore({reducer: mySlice, userId})

In mySlice.js

export const mySlice = createApi({
    reducerPath: 'api',
    baseQuery: fetchBaseQuery({
        baseUrl: `/common/path/${state.userId}/specific/path`
    }),
    endpoints: {4 endpoints defined here}
})

But this doesn't work, because state and getState are not accessible when creating the baseUrl.


Solution

  • But this doesn't work, because state and getState are not accessible when creating the baseUrl.

    They are actually, but you need to create a custom baseQuery function.

    See Implementing a custom baseQuery for details.

    Create a base query function that accesses the Redux api to access the current state at the time a request is made to compute the desired baseUrl value that is then passed along to the actual fetchBaseQuery you are using.

    Basic Example:

    import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
    
    const baseQuery = (baseQueryArgs = {}) => async (
      fetchArgs = {},
      api,
      extraOptions = {},
    ) => {
      const { getState } = api;
      const state = getState();
      const baseUrl = `/common/path/${state.userId}/specific/path`;
    
      return fetchBaseQuery({
        ...baseQueryArgs,
        baseUrl,
      })(fetchArgs, api, extraOptions);
    };
    
    export const mySlice = createApi({
      reducerPath: 'api',
      baseQuery: baseQuery(),
      endpoints: {/* 4 endpoints defined here */}
    });
    

    If you wanted this to be a little more robust you could pass a baseUrl string with some placeholder text that is replaced in baseQuery.

    Example:

    import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
    
    const baseQuery = (baseQueryArgs = {}) => async (
      fetchArgs = {},
      api,
      extraOptions = {},
    ) => {
      const { getState } = api;
      const state = getState();
      const baseUrl = baseQueryArgs.baseUrl.replace("{{userId}}", state.userId);
    
      return fetchBaseQuery({
        ...baseQueryArgs,
        baseUrl,
      })(fetchArgs, api, extraOptions);
    };
    
    export const mySlice = createApi({
      reducerPath: 'api',
      baseQuery: baseQuery({
        baseUrl: "/common/path/{{userId}}/specific/path",
      }),
      endpoints: {/* 4 endpoints defined here */}
    });