Mirror: The highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

docs(graphcache): Update cache update docs (#3334)

authored by

Phil Pluckthun and committed by
GitHub
80148efa 449c476a

+104 -10
+104 -10
docs/graphcache/cache-updates.md
··· 79 79 method that they call on the `cache` instance a side effect, which may trigger additional cache 80 80 changes and updates all affected queries as we modify them. 81 81 82 + ## Why do we need cache updates? 83 + 84 + When we’re designing a GraphQL schema well, we won’t need to write many cache updaters for 85 + Graphcache. 86 + 87 + For example, we may have a mutation to update a username on a `User`, which can trivially 88 + update the cache without us writing an updater because it resolves the `User`. 89 + 90 + ```graphql 91 + query User($id: ID!) { 92 + user(id: $id) { 93 + __typename # "User" 94 + id 95 + username 96 + } 97 + } 98 + 99 + mutation UpdateUsername($id: ID!, $username: String!) { 100 + updateUser(id: $id, username: $username) { 101 + __typename # "User" 102 + id 103 + username 104 + } 105 + } 106 + ``` 107 + 108 + In the above example, `Query.user` returns a `User`, which is then updated by a mutation on 109 + `Mutation.updateUser`. Since the mutation also queries the `User`, the updated username will 110 + automatically be applied by Graphcache. If the mutation field didn’t return a `User`, then this 111 + wouldn’t be possible, and while we can write an updater in Graphcache for it, we should consider 112 + this poor schema design. 113 + 114 + An updater instead becomes absolutely necessary when a mutation can’t reasonably return what has 115 + changed or when we can’t manually define a selection set that’d be even able to select all fields 116 + that may update. Some examples may include: 117 + 118 + - `Mutation.deleteUser`, since we’ll need to invalidate an entity 119 + - `Mutation.createUser`, since a list may now have to include a new entity 120 + - `Mutation.createBook`, since a given entity, e.g. `User` may have a field `User.books` that now 121 + needs to be updated. 122 + 123 + In short, we may need to write a cache updater for any **relation** (i.e. link) that we can’t query 124 + via our GraphQL mutation directly, since there’ll be changes to our data that Graphcache won’t be 125 + able to see and store. 126 + 127 + In a later section on this page, [we’ll learn about the `cache.link` method.](#writing-links-individually) 128 + This method is used to update a field to point at a different entity. In other words, `cache.link` 129 + is used to update a relation from one entity field to one or more other child entities. 130 + This is the most common update we’ll need and it’s preferable to always try to use `cache.link`, 131 + unless we need to update a scalar. 132 + 82 133 ## Manually updating entities 83 134 84 135 If a mutation field's result isn't returning the full entity it updates then it becomes impossible ··· 155 206 156 207 If we still manage to call any of the cache's methods outside its callbacks in its configuration, 157 208 we will receive [a "(2) Invalid Cache Call" error](./errors.md#2-invalid-cache-call). 209 + 210 + ### Updaters on arbitrary types 211 + 212 + Cache updates **may** be configured for arbitrary types and not just for `Mutation` or 213 + `Subscription` fields. However, this can potentially be **dangerous** and is an easy trap 214 + to fall into. It is allowed though because it allows for some nice tricks and workarounds. 215 + 216 + Given an updater on an arbitrary type, e.g. `Todo.author`, we can chain updates onto this field 217 + whenever it’s written. The updater can then be triggerd by Graphcache during _any_ operation; 218 + mutations, queries, and subscriptions. When this update is triggered, it allows us to add more 219 + arbitrary updates onto this field. 220 + 221 + > **Note:** If you’re looking to use this because you’re nesting mutations onto other object types, 222 + > e.g. `Mutation.author.updateName`, please consider changing your schema first before using this. 223 + > Namespacing mutations is not recommended and changes the execution order to be concurrent rather 224 + > than sequential when you use multiple nested mutation fields. 158 225 159 226 ## Updating lists or links 160 227 ··· 469 536 > confused with "real" data in your configuration. 470 537 471 538 In the following example we assume that we'd like to implement an optimistic result for a 472 - `favoriteTodo` mutation. The mutation is rather simple and all we have to do is create a function 539 + `favoriteTodo` mutation, like such: 540 + 541 + ```graphql 542 + mutation FavoriteTodo(id: $id) { 543 + favoriteTodo(id: $id) { 544 + id 545 + favorite 546 + updatedAt 547 + } 548 + } 549 + ``` 550 + 551 + The mutation is rather simple and all we have to do is create a function 473 552 that imitates the result that the API is assumed to send back: 474 553 475 554 ```js ··· 491 570 Once the mutation result comes back from our API this temporary change will be rolled back and 492 571 discarded. 493 572 494 - It's important to ensure that our optimistic mutations return all data that the real mutation may 495 - return. If our mutations request a field in their selection sets that our optimistic mutation 496 - doesn't contain then we'll see a warning, since this is a common mistake. To work around not having 497 - enough data we may use methods like `cache.readFragment` and `cache.resolve` to retrieve more data 498 - from our cache. 573 + In the above example optimistic mutation function we also see that `updatedAt` is not present in our 574 + optimistic return value. That’s because we don’t always have to (or can) match our mutations’ 575 + selection sets perfectly. Instead, Graphcache will skip over fields and use cached fields for any we 576 + leave out. This can even work on nested entities and fields. 577 + 578 + However, leaving out fields can sometimes cause the optimistic update to not apply when we 579 + accidentally cause any query that needs to update accordingly to only be partially cached. In other 580 + words, if our optimistic updates cause a cache miss, we won’t see them being applied. 581 + 582 + Sometimes we may need to apply optimistic updates to fields that accept arguments. For instance, our 583 + `favorite` field may have a date cut-off: 584 + 585 + ```graphql 586 + mutation FavoriteTodo(id: $id) { 587 + favoriteTodo(id: $id) { 588 + id 589 + favorite(since: ONE_MONTH_AGO) 590 + updatedAt 591 + } 592 + } 593 + ``` 499 594 500 - If we'd like to make sure we don't compute more fields than we need, for instance because one 501 - mutation is run with several different selection sets, then we may pass nested optimistic resolver 502 - functions in our optimistic object, like so: 595 + To solve this, we can return a method on the optimistic result our `optimistic` update function 596 + returns: 503 597 504 598 ```js 505 599 const cache = cacheExchange({ ··· 518 612 ``` 519 613 520 614 The function signature and arguments it receives is identical to the toplevel optimistic function 521 - you define. 615 + you define, and is basically like a nested optimistic function. 522 616 523 617 ### Variables for Optimistic Updates 524 618