You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: pg-todo-tutorial_section-3a.md
+103
Original file line number
Diff line number
Diff line change
@@ -428,3 +428,106 @@ Note the lack of useState or useEffect in all of the above queries/mutations. Wh
428
428
And thats all folks. Our todo list operates as it should...
429
429
430
430
Except that we do not yet get automatic updates from other sources of database writes. What is going on? What if my project-manager/editor/cat wants to see whats going on and maybe add or remove something from our all important task list? In Section 3 it will be back to the wonderful land of `PL/pgSQL`, `pg_notify()`, and then subscriptions for everyone.
431
+
432
+
### The Most Brief Postscript on Field Policies
433
+
434
+
Before we start with subscriptions I have decided I would rearrange my code todo list just a bit. The `TodoInput` component has been pulled out of the `TodoList` component and I thought maybe we could simplify the `GET_TODOS` cache update. There is a wonderful way in which we can define the `merge` function that apollo client will use for any particular field. By default incoming data replaces what exists in Apollo's cache. This is very sensible for simple types, but for more complex types, like objects and arrays, it is often preferable to "merge" the incoming data with the existing data. This is what we are explicitly doing with:
Apollo Client's `inMemoryCache` takes an optional `TypePolicy` object that allows for the definition of a [field policy][fieldpolicy]. The documentation is excellent on the subject so I will only say that we can define the default behavior of the cache as it pertains to merges(writing), reads(querying), and keys(identifying). We are concerned primarily with merges on our `todos` array so our `TypePolicy` will look like this:
450
+
451
+
```js
452
+
/* client/src/index.js*/
453
+
...
454
+
455
+
constclient=newApolloClient({
456
+
uri:'http://127.0.0.1:3333/graphql'/* variables from toplevel project .env */,
457
+
cache:newInMemoryCache({
458
+
typePolicies: {
459
+
Query: {
460
+
fields: {
461
+
todos: {
462
+
merge(existing= [], incoming) {
463
+
return [...existing, ...incoming];
464
+
},
465
+
},
466
+
},
467
+
},
468
+
},
469
+
})
470
+
});
471
+
472
+
...
473
+
```
474
+
475
+
We are just concatenating via spread syntax our existing `todos` field with incoming `todos`. Note that we provide a default argument for `existing` as an empty array so that when we have no `todos` (like on startup) our client will not crash.
476
+
477
+
Now to simplifying our cache update in `TodoInput`:
478
+
479
+
```js
480
+
/* client/src/TodoInput.js */
481
+
482
+
const [createTodo] =useMutation(CREATE_TODO, {
483
+
update: (cache, mutationResult) => {
484
+
cache.writeQuery({
485
+
query:GET_TODOS,
486
+
data: {
487
+
todos: [mutationResult.data.createTodo.todo],
488
+
},
489
+
});
490
+
},
491
+
});
492
+
```
493
+
494
+
We remove our `readQuery` and simply define data as the incoming todo (as an array!). Note that we can no longer use the `readQuery`/`writeQuery` approach to delete from the cache.
495
+
496
+
...And another good example of the use of the `TypePolicy` object. At the beginning of this section I opted to use set the `classicIds:true` option for postgraphile. This allowed Apollo Client to properly identify each `todo` by its `NodeId` instead of its postgres `id` field. This in turn allowed us to easily identify our todo when updating the cache. The `keyFields` property of `TypePolicy` lets us use any field to identify an object in the cache. Using nodeId would look like:
497
+
498
+
```js
499
+
/* client/src/index.js*/
500
+
...
501
+
502
+
constclient=newApolloClient({
503
+
uri:'http://127.0.0.1:3333/graphql'
504
+
cache:newInMemoryCache({
505
+
typePolicies: {
506
+
Todo: {
507
+
keyFields: ["nodeId"]
508
+
},
509
+
}
510
+
})
511
+
});
512
+
...
513
+
```
514
+
515
+
Try it out. We will continue to use `classicIds:true` in for the foreseeable future, but its nice to know we have options. { dataIdFromObject: (object) => object.nodeId }
0 commit comments