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.

Cache FieldPolicy.merge receives stale args when using fetchMore

See original GitHub issue

I am not shure if this is a bug or if i am using fetchMore in the wrong way. Help would be greatly appreciated.

Intended outcome: When using fetchMore for a pagination query FieldPolicy.merge should be called with FieldFunctionOptions.args that correspond to the variables given to fetchMore.

Actual outcome: FieldFunctionOptions.args always contains the field variables of the initial query (e.g. limit: 30, offset: 0). Even if fetchMore was called with e.g. offset: 10.

Code Client configuration

return new ApolloClient({
    cache: new InMemoryCache({
        typePolicies: {
            LogEntryPagination: {
                fields: {
                    rows: {
                        keyArgs: false,
                        merge(existing: any[], incoming: any[], params) {
                            const offset = params.variables.offset;
                            const merged = existing ? existing.slice(0) : [];
                            // Insert the incoming elements in the right places, according to args.
                            const end = offset + incoming.length;
                            for (let i = offset; i < end; ++i) {
                                merged[i] = incoming[i - offset];
                            }
                            return merged;
                        },
                    },
                },
            },
        },
    }),
    link,
    queryDeduplication: true,
    defaultOptions: {
        query: {
            errorPolicy: 'all',
        },
        mutate: {
            errorPolicy: 'all',
        },
    },
});

Query

query ListLogEntries(
    $limit: Int!
    $offset: Int!
    $order: [String]
    $site: ID
) {
    logEntries(
        order: $order
        site: $site
    ) {
        count
        rows(limit: $limit, offset: $offset) {
            ...LogEntry
        }
    }
}

Custom Query hook

export const useListLogs = (siteId: string, limit: number) => {
    const {data, loading, error, fetchMore} = useQuery(
        ListLogEntries,
        {
            variables: {
                site: siteId,
                offset: 0,
                limit,
            },
            notifyOnNetworkStatusChange: true,
        }
    );
    return {
        logs: data?.logEntries,
        fetchMoreLogs: fetchMore,
        isLoadingLogs: loading,
    };
};

Use of query hook in component

const {logs, fetchMoreLogs, isLoadingLogs} = useListLogs(siteId, batchSize);
return ( 
    <VirtualizedTable
        loadMoreRows={async (offset, limit) => {
            await fetchMoreLogs({
                variables: {
                    limit,
                    offset,
                },
            });
        }}>
);

Versions

  System:
    OS: Windows 10 10.0.18363
  Binaries:
    Node: 12.6.0
    Yarn: 1.21.1
    npm: 5.1.0
  npmPackages:
    @apollo/client: ^3.0.0-beta.34
    apollo-link-error: ^2.0.0-beta.0

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:1
  • Comments:11 (2 by maintainers)

github_iconTop GitHub Comments

11reactions
benjamncommented, Jun 12, 2020

Thanks @chrisgco! Your diagnosis is absolutely correct, and you made my job a lot easier by sharing your findings.

I want to apologize to everyone here for the sorry shape of fetchMore in AC3. I hope it hasn’t been keeping you from using the betas/RCs, though I wouldn’t blame you if it did. I believe the new field policy API (read and merge functions and keyArgs) will make pagination a lot easier and more reliable in AC3, but that doesn’t matter if fetchMore is unable to cooperate with merge functions.

We should have this fixed (and more thoroughly tested) very soon.

5reactions
cbergmillercommented, Feb 17, 2020

@benjamn you are right, i should have used params.args.offset in my example. However, args also hold the values of the initial query when using fetchMore. For now i am using updateQuery in the fetchMore options to merge the results.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Advanced topics on caching in Apollo Client
Advanced topics on caching in Apollo Client. This article describes special cases and considerations when using the Apollo Client cache. Bypassing the cache....
Read more >
ApolloClient fetchMore with custom merge updates cache, but ...
I forced rerendering by adding networkStatus to my query result, but I didn't get the merged result form the cache either (but the...
Read more >
apollo-client - Awesome JS
In Apollo Client 2.x, a refetch operation would always replace existing data in the cache. With the introduction of field policy merge functions...
Read more >
Apollo Client 3 cache management of cursor-paginated lists
These are notes and findings related to building the Apollo Client cache for ... FieldPolicy { return { keyArgs: false, merge(existing, incoming) {...
Read more >
@apollo/client | Yarn - Package Manager
npm version Build Status Join the community. Apollo Client is a fully-featured caching GraphQL client with integrations for React, Angular, and more.
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