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.

Refetch should not trigger a field merge

See original GitHub issue

Intended outcome:

From the docs for refetch:

Update the variables of this observable query, and fetch the new results

It seems wrong to me that when the new results come back it triggers the field’s merge function. As we are resetting the variables the previous value for the query should be considered invalid and thrown out implicitly.

If there is not agreement on the above proposition, at the very least I would like to have a way to know that I’m in a merge function as the result of a refetch, so I can throw out the previous result explicitly.

Actual outcome:

The field’s merge function is triggered and new results are merged with the old, creating an erroneous cache entry that results from a combination of old variable values and new.

How to reproduce the issue:

This is default behavior, trigger a refetch on a query whose result has a custom field merge policy. The problem is most easily identified in the context of list type fields and pagination.

Versions

  System:
    OS: macOS 10.15.7
  Binaries:
    Node: 12.18.2 - ~/.nvm/versions/node/v12.18.2/bin/node
    npm: 6.14.5 - ~/.nvm/versions/node/v12.18.2/bin/npm
  Browsers:
    Chrome: 87.0.4280.88
    Firefox: 79.0
    Safari: 14.0.2
  npmPackages:
    @apollo/client: 3.0.0-rc.4 => 3.0.0-rc.4
    apollo-angular: ^2.0.0-beta.2 => 2.0.0-beta.2

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:14
  • Comments:13 (4 by maintainers)

github_iconTop GitHub Comments

5reactions
benjamncommented, Feb 3, 2021

Here’s my current thinking on the original issue, as reported by @vigie and echoed by @JeffJankowski:

If you define a merge function for a field, InMemoryCache must call that function any time new data is written for that field, even the very first time (when the existing data is undefined), because merge functions give you the ability to customize the internal representation of field data within the cache. If merge was called most of the time but not all the time, it would be very difficult to know what type of data to expect when reading from the cache.

However, I believe we can preserve this guarantee (that merge is always called) while achieving the behavior @vigie is proposing, by providing a way to call merge functions with undefined existing data, so they behave exactly as they would if there was no existing data, and thus do not attempt to combine incoming data with existing data (but still potentially transform the incoming data, as appropriate).

My current plan is to add an overwrite?: boolean option to the cache.writeQuery and cache.writeFragment option types. It will be false by default, but passing overwrite: true will prevent any merge functions involved in the write from seeing any existing data, thereby overwriting those field values. For fields that do not have a merge function, new field data always replaces existing data, so you can think of overwrite: true as a way to achieve that default behavior even when you have a merge function.

Of course, since you don’t manually call cache.writeQuery when you’re using refetch, we will need to arrange for overwrite: true to be passed behind the scenes, when refetch does its cache write. I agree this should be the default behavior for refetch, but we may need to make it optional (opt-in) to avoid breaking changes.

I welcome your thoughts/questions about this idea. It is straightforward to implement, but needs more unit tests. I’ll kick off a PR tomorrow, with the goal of releasing it in Apollo Client 3.4 (and in the next beta release, more immediately).

The issue @jtoce identified in https://github.com/apollographql/apollo-client/issues/7491#issuecomment-767985363 may well be a contributing factor (preventing writes in some cases, thereby not triggering any merge functions), but that should be easy to fix by deleting queryInfo.lastWrite before refetching. I’ll put that change in the PR too.

4reactions
Akryumcommented, Apr 1, 2021

Really need this to be fixed, as I can’t both use fetchMore and refetch while migrating from Apollo Client 2 to 3, refetch being broken (the merge logic doesn’t have the info if the cache write is a pagination or a refetch). 😅 🙏

Read more comments on GitHub >

github_iconTop Results From Across the Web

Use fetchMore and merge field policies to dynamically load ...
For this, we'll start off by looking at the fetchMore utility, that is provided by the useQuery hook, to trigger loading of more...
Read more >
Apollo fails to merge cache on refetch call - Stack Overflow
The solution to this is an as yet seemingly undocumented option that can be passed to either the apollo client instantiation or the...
Read more >
Customizing the behavior of cached fields - Apollo GraphQL
Merging non-normalized objects. You can use a merge function to intelligently combine nested objects that are not normalized in your cache, assuming those ......
Read more >
Customizing the behavior of cached fields - Client (React)
You can customize how a particular field in your Apollo Client cache is read ... field merge functions is to combine nested objects...
Read more >
Get Merge Fields from Zoho Writer | Help - Zoho Deluge
You will not get the expected result if you execute zoho.writer.getMergeFields task before the document from which you need to fetch merge fields...
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