18

I just started on redux yesterday and after reading up on the different libraries, I decided to use the slice route from RTK.

For my async, instead of using createAsyncThunk, I decided to use RTK query and I have a question on the right way to access state from another slice.

slice1 contains some user data for example:

export const initialState: IUserState = {
   name: 'example',
   id: null,
};

and in my slice2, I have a function that wants to do something like getSomethingByUserId(id) and my current implementation:

interface IApiResponse {
  success: true;
  result: IGotSomethingData[];
}

const getsomethingSlice: any = createApi({
  reducerPath: 'api',
  baseQuery: fetchBaseQuery({
    baseUrl: 'https://someapibase',
  }),
  endpoints(builder) {
    return {
      fetchAccountAssetsById: builder.query<IApiResponse, null>({
        query() {
          console.log('store can be called here', store.getState().user.id);
          return `/apipath?id=${store.getState().user.id}`;
        },
      }),
    };
  },
});

export default getsomethingSlice;
export const { useFetchAccountAssetsByIdQuery } = getsomethingSlice;

As I read somewhere that markerikson mentioned it's not good practice to import the store but to use getState in thunk, I took a look around and see in the documentations that there is getState for query which exist in the onStart unlike thunk which you can access it from it's second parameter.

Do anyone have a onStart implementation for this? Or is importing store acceptable for this?

phry
  • 35,762
  • 5
  • 67
  • 81
LuxuryWaffles
  • 1,518
  • 4
  • 27
  • 50

1 Answers1

26

Generally, we want to prevent people from doing that, which is why you don't have getStore available there (you have at many other places).

You see, RTK-query uses the argument you give into the query to determine the cache key. Since you don't pass in an argument, the cache key the result would be stored as fetchAccountAssetsById(undefined).

So, you make a first request, state.user.id is 5 and that request is made.

Now, your state.user.id changes to 6. But your component calls useFetchAccountAssetsByIdQuery() and there is already a cache entry for fetchAccountAssetsById(undefined), so that is still being used - and no request is made.

If your component instead would be calling useFetchAccountAssetsByIdQuery(5) and it changes to useFetchAccountAssetsByIdQuery(6), RTK-query can safely identify that it has a cache entry for fetchAccountAssetsById(5), but not for fetchAccountAssetsById(6) and will make a new request, retrieving up-to-date information.

So, you should select that value in your component using useSelector and pass it into your query hook as an argument, not pull it out of the store in your query function.

phry
  • 35,762
  • 5
  • 67
  • 81
  • I see, what about onStart’s getState? – LuxuryWaffles Jun 06 '21 at 11:38
  • 2
    `onStart` is `onQueryStarted` now, please take a look at [the current RC docs](https://deploy-preview-1016--redux-starter-kit-docs.netlify.app/rtk-query/api/createApi#onquerystarted). Generally, there you are doing a side effect that takes place after the decision has been made that that query should be running. So the whole thing doesn't play a role there. – phry Jun 06 '21 at 11:41
  • @phry Does your answer also apply for common path parameters? In our case, most endpoints start with `users/${id}`. – alexander May 02 '23 at 03:43
  • 1
    @alexander usually I'd recommend to wrap your hooks in custom ones, but you *can* do something like this in a custom wrapped `baseQuery`. Just be aware that you essentially disable cache for that. – phry May 02 '23 at 06:06
  • 1
    Well, I see. For now I will stick to the pattern to hand over the parameter from the caller to the query like `useRecords({ userId: user.id, date: toDateString(selectedDate) })` where as the `user.id` comes from some state. – alexander May 02 '23 at 06:40
  • @phry is it ok to access state via queryFn api to transform a response? – Anthony Jul 18 '23 at 17:58
  • @Anthony you have to be aware that if the state changes later, your transformed response will not magically change accordingly. Usually, it would be better to do something like that outside of RTK Query. – phry Jul 18 '23 at 18:12
  • @phry the state I'm accessing is immediately triggering (when changed) the query that I'm transforming, so the query is always up to date. I'm passing a sub-set (array of ids) of that state to the query but perhaps I should just pass the entire state and then I would have access to it via the query arg. The thought was to minimize the amount of data I'm passing. – Anthony Jul 18 '23 at 19:01
  • @Anthony If your query depends on it, passing it in as an arg would be best. – phry Jul 19 '23 at 05:53