RTK Query: createApi's merge method not getting called

832 Views Asked by At

Intro:

I am using createApi to set an endpoint that returns picsum pictures as a list. Since the list endpoint of picsum api does not provide resized versions of the pictures, I am using queryFn to trick it into doing so (it's just updating the url property). Then I pass this list of urls to img tags.

Mission:

I need to implement an infinite scroller. To do so I've used serializeQueryArgs and merge properties. I want the cache to be kept despite the page changing, since I need to merge the new results with it every time I hit "Load more". I've put some console.logs to see what's happening.

picsumApi.ts

import { MaybePromise } from "@reduxjs/toolkit/dist/query/tsHelpers";
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";

const BASE_URL = "https://picsum.photos";

async function tryMaybePromise(maybePromise: MaybePromise<any>) {
  const response = await maybePromise;
  if (response.error) throw response.error;
  return response.data;
}

export const picsumApi = createApi({
  reducerPath: "picsumApi",
  baseQuery: fetchBaseQuery({ baseUrl: BASE_URL }),
  endpoints: (builder) => ({
    getPictures: builder.query<
      PicsumThumbnail[],
      { page?: number; limit?: number }
    >({
      queryFn: async ({ page, limit }, _api, _opt, fetchWithBQ) => {
        console.log("queryfn");

        const picsumThumbnails = (await tryMaybePromise(
          fetchWithBQ({
            url: "v2/list",
            params: { page, limit },
          })
        )) as PicsumThumbnail[];

        for (const pi of picsumThumbnails) {
          pi.url = BASE_URL + `/id/${pi.id}/300/200`;
        }

        return { data: picsumThumbnails };
      },
      serializeQueryArgs: ({ queryArgs }) => {
        console.log("serializeQueryArgs");
        const { page, ...otherArgs } = queryArgs;
        return otherArgs;
      },
      merge: (currentCache, newItems) => {
        console.log("merge");
        currentCache.push(...newItems);
      },
    }),
    getPictureById: builder.query<PicsumThumbnail, string>({
      query: (id) => `/${id}/300/200`,
    }),
  }),
});

// Export hooks for usage in functional components, which are
// auto-generated based on the defined endpoints
export const { useGetPicturesQuery, useGetPictureByIdQuery } = picsumApi;

page.tsx

"use client";
import { useGetPicturesQuery } from "@/redux/services/picsumApi";
import { Button } from "@radix-ui/themes";
import Image from "next/image";
import React, { useEffect, useState } from "react";

export default function HomePage() {
  const [page, setPage] = useState(1);
  const {
    data: pictures,
    error,
    isLoading,
  } = useGetPicturesQuery({ page, limit: 4 });

  return (
    <div>
      {pictures?.map(({ id, url }) => (
        <Image key={id} width={300} height={200} alt={String(id)} src={url} />
      ))}
      <Button
        onClick={() => {
          setPage((prevPage) => prevPage + 1);
        }}
      >
        Load more
      </Button>
    </div>
  );
}

Problem:

When the page first loads, I get the "queryFn" and "serializeQueryArgs" logs in the console. When I hit "Load more", I get "serializeQueryArgs". But I never receive the "merge" log.

I don't know what else to try. I can't find any example of queryFn together with merge. Maybe they are incompatible? I can't find any explaination in RTK Query documentation.

Why does the merge method never get called?

1

There are 1 best solutions below

1
On BEST ANSWER

Since RTKQ normally replaces cache entries with the new response, you will usually need to use this with the serializeQueryArgs or forceRefetch options to keep an existing cache entry so that it can be updated.

docs: https://redux-toolkit.js.org/rtk-query/api/createApi