Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

- Documentation: added some details about cache updates #11152

Merged
merged 5 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/source/api/cache/InMemoryCache.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -1092,7 +1092,7 @@ The full key for the field used internally, including serialized key arguments.
</td>
<td>

A helper function for reading other fields within the current object.
A helper function for reading other fields within the current object, i.e. the object passed as first parameter.
alessbell marked this conversation as resolved.
Show resolved Hide resolved
</td>
</tr>

Expand Down
6 changes: 4 additions & 2 deletions docs/source/caching/cache-interaction.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ Apollo Client supports multiple strategies for interacting with cached data:
| [Using GraphQL fragments](#using-graphql-fragments) | `readFragment` / `writeFragment` / `updateFragment` / `useFragment` | Access the fields of any cached object without composing an entire query to reach that object. |
| [Directly modifying cached fields](#using-cachemodify) | `cache.modify` | Manipulate cached data without using GraphQL at all. |

You can use whichever combination of strategies and methods are most helpful for your use case.
You can use whichever combination of strategies and methods are most helpful for your use case.

Changing cache fields with these methods will only affect the objects at the very place you specify by the query, the fragment or the location of the `modify` call. So, if you're changing an object at a nested place from `{__ref: '5'}` to `{__ref: '5', completed: true}`, this will override the `completed` value for cache reads at the specific place, but nowhere else.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little confused by the use of "place" here: do you mean the particular reference?

@bignimbus , since you were part of the original discussion maybe you have some insight?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With "place" I mean what I'm specifying with a fragment or query, e.g. an object with id: 5 in a result at 'ROOT_QUERY.myEntities("orderBy": "size", "pagination": {"first": 20, "cursor": 1234})'. Changing a value of this object there won't affect the object with the same __ref/id in, say, 'ROOT_QUERY.myEntities("orderBy": "age", "pagination": {"first": 20, "cursor": 1234})', and neither the object itself, stored at the root level (__APOLLO_CLIENT__.data.data). At least that's what I understood from the original discussion,

I'm not sure what you mean with "particluar reference" - the Reference object or the pointer to the updated ... eh ... location in the cache. It's really hard to find the right words when everything seems to have a double meaning: a naive one and one specififc for the Apollo Cache domain. :D

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the tag! Should we consider a different approach here? We have documentation about __ref objects. We could link to this url. Ex:

Suggested change
Changing cache fields with these methods will only affect the objects at the very place you specify by the query, the fragment or the location of the `modify` call. So, if you're changing an object at a nested place from `{__ref: '5'}` to `{__ref: '5', completed: true}`, this will override the `completed` value for cache reads at the specific place, but nowhere else.
Bear in mind the difference between fields that contain references to other objects in the cache and fields that contain literal values. References are objects that contain a `__ref` field (read more [here](https://www.apollographql.com/docs/react/caching/overview/#example)). Modifying a reference will not change the values contained in the object to which the reference points. So avoid updating an object from something like `{__ref: '5'}` to `{__ref: '5', completed: true}`.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two things:

  • You're using a double space between sentences. It that common? I think I haven't seen that elsewhere in the documentation.
  • Why should I avoid doing to update an object to {__ref: '5', completed: true}? I my case, I wanted to update a query result with a generic utility method (for modyfing pagination results), so I did exactly that. This generic method has no knowledge about the underlying data or let alone its type, and since cache.modify does not come with a straight-forward way to fetch the referenced item, I went with:
const myModifier: Modifier<Reference> = (prevData, details) => {
   return {
      ... prevData,
      someField: 'updatedValue'
   }
}

and thought: 'Well, for my current component it's enough since my updatedValue will be regarded there, and for other the data will be reloaded anyway!' (depends on the fetch policy ofc.). This is why I created the issue at the first place - b/c I wasn't sure that intended, and by the and, I figured it was. :D

Copy link
Contributor

@bignimbus bignimbus Aug 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the reply @JonasDoe! My two cents: there's nothing explicitly wrong with doing what you're doing, it's just not a pattern that I think the maintainers should explicitly support. Reference objects are intended to point to other objects, the fact that they can be arbitrarily extended to include value literals is just a feature of JavaScript, not an intentional design choice of Apollo Client. I hope that clarifies things! Happy to go to single spaces after periods, it's just a habit of mine to do double spaces. I believe HTML will render the same thing either way.

Copy link
Contributor Author

@JonasDoe JonasDoe Aug 24, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I screwed something up. I wanted to reply here with an suggestion, but commited your proposal of this part, as it seems. Anyway, then I try it the old way:
I'ld suggest something as

So avoid updating an object from something like `{__ref: '5'}` to `{__ref: '5', completed: true}` if you want to update more than that specific query result.

to clarify the discouragement.


> All code samples below assume that you have initialized an instance of `ApolloClient` and that you have imported the `gql` function from `@apollo/client`. If you haven't, [get started](../get-started).
>
Expand Down Expand Up @@ -321,7 +323,7 @@ cache.modify({

When you define a modifier function for a field that contains a scalar, an enum, or a list of these base types, the modifier function is passed the exact existing value for the field. For example, if you define a modifier function for an object's `quantity` field that has current value `5`, your modifier function is passed the value `5`.

**However**, when you define a modifier function for a field that contains an object type or a list of objects, those objects are represented as **references**. Each reference points to its corresponding object in the cache by its cache ID. If you return a _different_ reference in your modifier function, you change _which_ other cached object is contained in this field. You _don't_ modify the original cached object's data.
**However**, when you define a modifier function for a field that contains an object type or a list of objects, those objects are represented as **references**. Each reference points to its corresponding object in the cache by its cache ID. If you return a _different_ reference in your modifier function, you change _which_ other cached object is contained in this field. You _don't_ modify the original cached object's data. Additionally, modifying a field (or adding a new one) in a reference will only take effect for the location you're modifying.
Meschreiber marked this conversation as resolved.
Show resolved Hide resolved

### Modifier function utilities

Expand Down