Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question] : Generic solution for prefetching paginated queries #4149

Closed
julien-tricent opened this issue Feb 2, 2024 · 5 comments
Closed

Comments

@julien-tricent
Copy link

julien-tricent commented Feb 2, 2024

Hey!

So I have an Api object generated by RTKQ-Codegen. There is a large amount of endpoint and most of them have server-side pagination (i.e page and pageSize parameters).

I would like to know if it's possible to implement a generic solution (maybe a middleware?) to prefetch the next page of any query that have been fulfilled, if it had a page argument.

Something like :

import { Middleware } from '@reduxjs/toolkit';
import { myApi } from 'src/api/enhancedApi';
import { RootState } from './store';

const fetchNextPageMiddleware: Middleware<unknown, RootState> =
  ({ getState, dispatch }) =>
  (next) =>
  (action) => {
    if (action.type === 'api/executeQuery/fulfilled' && typeof action.meta.arg.originalArgs.page === 'number') 
    {
      dispatch(myApi.util.prefetch(action.meta.arg.endpointName,
        {
          ...action.meta.arg.originalArgs,
          page: action.meta.arg.originalArgs.page + 1,
        },
        {},
      ));
    }
    return next(action);
  };

However I got some typing issues because action is of type unknown. Which means I have to manually check each property.

The dispatch also doesn't allow me to actually dispatch the prefetch because the later returns a ThunkAction

@julien-tricent julien-tricent changed the title [Question] : Generic solution for prefetching queries [Question] : Generic solution for prefetching paginated queries Feb 2, 2024
@EskiMojo14
Copy link
Collaborator

You can somewhat unsafely skip some steps using type predicates:

import { Middleware, ThunkDispatch, UnknownAction, isFulfilled } from '@reduxjs/toolkit';
import { myApi } from 'src/api/enhancedApi';
import { RootState } from './store';

const hasEndpointName = (arg: any): arg is { endpointName: string } =>
  typeof arg?.endpointName === "string";

const hasPage = (arg: any): arg is { originalArgs: { page: number } } =>
  typeof arg?.originalArgs?.page === "number";

const fetchNextPageMiddleware: Middleware<
  unknown,
  RootState,
  ThunkDispatch<RootState, unknown, UnknownAction>
> =
  ({ getState, dispatch }) =>
  (next) =>
  (action) => {
    if (
      isFulfilled(action) &&
      hasEndpointName(action.meta.arg) &&
      hasPage(action.meta.arg)
    ) {
      dispatch(
        myApi.util.prefetch(
          action.meta.arg.endpointName as any,
          {
            ...action.meta.arg.originalArgs,
            page: action.meta.arg.originalArgs.page + 1,
          },
          {},
        ),
      );
    }
    return next(action);
  };

Ultimately though, unless you maintain a list of possible endpoints, it will be difficult to prove to Typescript that endpointName is correct (hence the as any)

@julien-tricent
Copy link
Author

julien-tricent commented Feb 8, 2024

@EskiMojo14 Very cool thanks, I've also manage to not use any.

However, I am more bothered of something else.
Is there any way to detect that the action is a prefetch action ? Because it keeps on dispatching prefetch page + 1 each time a prefetch is fullfiled

@EskiMojo14
Copy link
Collaborator

no, the action will be identical to other fetches.

@julien-tricent
Copy link
Author

Would it be ok to add that isPrefetch metadata in the action ?

@julien-tricent
Copy link
Author

Thanks for helping!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants