How get typePolicies and offsetLimitPagination to work with nested array in query in Apollo Client 3

In my React and TypeScript app, I am trying to implement pagination (fetch more items) with Apollo Client version 3.3.19 and GraphQL.

I have the following GraphQL query provided from the server:

import { gql } from '@apollo/client';

export const GET_NODES = gql`
  query GetNodes($limit: Int, $offset: Int) {
    getNodes(abstractKey: limit: $limit, offset: $offset) {
      pagination {
        hasNextPage
        totalItems
      }
      nodes {
        id
        title
      }
    }
  }
`;

My React component:

/** @jsx jsx */
import { useCallback } from 'react';

import { useQuery } from '@apollo/client';
import { jsx } from '@emotion/react';

import { GET_NODES } from './MyBlock.gql';
import {
  Props,
  GqlRes,
  NodesArgs,
} from './MyBlock.types';

const MyBlock = ({ data: blockData, metadata, offset, limit }: Props) => {

  const { loading, data, fetchMore } = useQuery<
    GqlRes,
    NodesArgs
  >(GET_NODES, {
    variables: {
      offset,
      limit,
    },
    errorPolicy: 'all',
    notifyOnNetworkStatusChange: true,
    ssr: false,
  });

  const fetchNext = useCallback(() => {
    return fetchMore({
      variables: {
        offset: data?.getNodes.nodes.length,
      },
     },
    });
  }, [nodes]);

  const myItems =
    data.getNodes.nodes.map((item) => {
        return {
          id: item.id,
          title: item.title,
        };
      }) || [];

  if (loading) {
    return 'Loading...';
  }

  return myItems?.length ? (
        <Carousel
          items={myItems}
          onReachEnd={() => {
            if (nodes?.getNodes.pagination.hasNextPage) {
              fetchNext();
            }
          }}
        />
  ) : null;
};

export default MyBlock;

Then in a file cache.ts I have the typePolicies:

export const cacheOpts: InMemoryCacheConfig = {
  possibleTypes,
  typePolicies: {
    Query: {
      fields: {
        nodes: offsetLimitPagination(),
      },
    },
  },
};

Now when I test the carousel it renders the first 12 items. When I reach the last item and click the right-arrow button to fetch more results, the component re-renders and in the console I can see a new GraphQL request with the next chunk of items in the response. But in the frontend, in the ui it’s not visible? You can’t navigate further then the 12th item, so the array (prev and next) isn’t merged.

How do I use typePolicies and offsetLimitPagination with a nested array? In the docs they are working with a root field which is the array.

How do I get this to work?

Hey I had a similar problem! For mine to work, I had to write a custom type policy with a merge function as shown in the docs - the mistake I was making was that I was not returning exactly the same type as the originating response from the component. Once I make sure the exact same type was returned from the merge function, the component updated.

Great opportunity to learn/write about my experience in this article - Nested Pagination with Apollo Client 3 | by Nick McLean | Feb, 2022 | Medium

Hey Nick - I need to figure this out and visited your medium post, which looks like it’ll do the trick, but none of your images are showing. Do you have the article somewhere with all the code examples?

1 Like

Hey there - I’ll get this fixed today! I’ll be home in a few hours to check this out. Thanks for letting me know!

My problem was with the merge function itself. The result needs to look exactly like the initial response from the graphql server to update the component. Is that what you are having problems with?

For some reason medium deleted all the links to gists… werid!

I re-linked them - so it should be up again

Let me know how it goes, happy to help if ya need it!