question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

fetchMore with variables doesn't update field policy read args

See original GitHub issue

Hi guys. I’m trying to get used to using typePolicies, it’s awesome to have the logic in a single point instead of every updateQuery, but when I do a fetchMore() it seems like the args from the read() aren’t updated like the merge() and I need them to do a Paginated view as in Paginated read functions.

Intended outcome: Get the same args in read() as in merge() on every update with fetchMore() .

Actual outcome: args in read() doesn’t update with fetchMore().

How to reproduce the issue:

TypePolicy:

    {
      ProductsType: {
        fields: {
          getPackProducts: {
            keyArgs: false,
            read(exists, { args }) {
              // args.skip and args.first are the same
              // as the original query, always. Not ok
              return exists && exists.slice(args.skip, args.first + args.skip);
            },
            merge(existing, incoming, { args }) {
              // args.skip and args.first are the original values (first)
              // and updates (skip) on each fetchMore. OK
              const merged = existing ? existing.slice(0) : [];
              const start = args ? args.skip : merged.length;
              const end = start + incoming.length;
              for (let i = start; i < end; ++i) {
                merged[i] = incoming[i - start];
              }
              return merged;
            }
          }
        }
      }
    }

Query:

const GET_PACKS = gql`
  query($first: Int, $skip: Int) {
    myProducts {
      getPackProducts(first: $first, skip: $skip) {
        id
      }
    }
  }
`;

useQuery hook:

const { loading, error, data, fetchMore } = useQuery(
  GET_PACKS,
  {
    variables: {
      skip: 0,
      first: 10
    }
  }
);

fetchMore

<button onClick={() => {
  fetchMore({
    variables: {
      skip: 20
    }
  })
}}>Next</button>

Versions

System:
  OS: macOS 10.15.7
Binaries:
  Node: 10.15.1 - ~/.nvm/versions/node/v10.15.1/bin/node
  Yarn: 1.22.10 - /usr/local/bin/yarn
  npm: 6.14.9 - ~/.nvm/versions/node/v10.15.1/bin/npm
Browsers:
  Chrome: 87.0.4280.88
  Firefox: 84.0
  Safari: 14.0
npmPackages:
  @apollo/client: ^3.3.6 => 3.3.6

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:9
  • Comments:6 (2 by maintainers)

github_iconTop GitHub Comments

21reactions
stevenmusumechecommented, Apr 13, 2021

This is really surprising behavior. Why wouldn’t you want the updated query variables in your read function?

8reactions
rossm6commented, Oct 9, 2021

Ah…

I’ve been using apollo for months and can’t believe I’ve only just discovered this.

In fact two recent discoveries which struck me as odd together now make sense.

The first discovery was the following query will execute again when the variables passed to the hook change. Hitherto I’d always assumed that fetchMore was the only way of getting further data for the original query set up in the hook. In fact I questioned whether this was intended behaviour here because I couldn’t understand why this would be - https://github.com/apollographql/apollo-client/issues/8847

function SomeComponent () {
    const { data, loading, fetchMore } = useQuery(GET_YOUR_LISTINGS, {
        fetchPolicy: 'network-only',
        nextFetchPolicy: 'cache-first',
        variables: {
            filters: {
                ...args.filters
            },
            orderBy: getOrderingForServer(args.orderBy),
            first: PAGE_SIZE,
            after: ''
        }
    });
}

Today I stumbled upon this issue because I too noticed that args passed to read did not reflect variables passed to fetchMore.

So my first discovery is the solution for ensuring the correct args are passed to read.

Together I now have something like this -

function SomeComponent () {
    const [args, setArgs] = useState();
    const [fetchInitial, { data, loading, fetchMore, called }] = useLazyQuery(GET_YOUR_LISTINGS, {
        fetchPolicy: 'network-only',
        nextFetchPolicy: 'cache-first',
        variables: {
            filters: {
                ...args.filters
            },
            orderBy: getOrderingForServer(args.orderBy),
            first: PAGE_SIZE,
            after: ''
        }
    });

   const fetchCount = useRef(0);
   if(called) fetchCount.current = 1;

    useEffect(() => {
       if(!args) return
       if(!fetchCount.current){
         fetchInitial();
       }
    }, [args, fetchInitial]);

    // fetchMore is then passed to a child infinite scroll component

    return (
     null
    )
}

I’m sure last time I read the docs for the Query section where fetchMore is first introduced this is not discussed. I’d strongly recommend changing the docs so that users new to apollo understand from the beginning that fetchMore really means fetchMore of the original query. I’m sure many like me just assumed it was the ONLY WAY of getting anything more from the original query.

Read more comments on GitHub >

github_iconTop Results From Across the Web

fetchMore not updating the data - Help - Apollo GraphQL
I'm using the fetchMore() function against a button click to show the updated data but the ... Added the field policy to the...
Read more >
Graphql - Apollo Client/ React - Cache - fetchMore doesn't ...
In the documentation examples, the arg used as the key is a primitive value, ... It is not a field to customize the...
Read more >
Pagination – Angular - GraphQL Code Generator
Apollo lets you do pagination with a method called fetchMore . ... To set keyArgs for the field policy generated by offsetLimitPagination ...
Read more >
GraphQL nested pagination with Apollo Client and React
With a field policy we can tell Apollo how to read and write fields ... Every time we create a query Apollo gives...
Read more >
Use fetchMore and merge field policies to dynamically load ...
Then, we'll look at defining a merge field policy, to define how these new ... how it helps us define by which variables...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found