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: docs/source/caching/cache-interaction.mdx
+130Lines changed: 130 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -13,6 +13,7 @@ Apollo Client supports multiple strategies for interacting with cached data:
13
13
|[Using GraphQL queries](#using-graphql-queries)|`readQuery` / `writeQuery` / `updateQuery`| Use standard GraphQL queries for managing both remote and local data. |
14
14
|[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. |
15
15
|[Directly modifying cached fields](#using-cachemodify)|`cache.modify`| Manipulate cached data without using GraphQL at all. |
16
+
|[Batching cache operations](#using-cachebatch)|`cache.batch`| Group multiple cache operations into a single transaction for better performance. |
16
17
17
18
You can use whichever combination of strategies and methods are most helpful for your use case.
18
19
@@ -302,6 +303,135 @@ The update function's return value is passed to either `writeQuery` or `writeFra
302
303
303
304
> See the full API reference for [`cache.updateQuery`](../api/cache/InMemoryCache/#updatequery) and [`cache.updateFragment`](../api/cache/InMemoryCache/#updatefragment).
304
305
306
+
### Using `cache.batch`
307
+
308
+
Use `cache.batch` to group multiple cache operations into a single transaction. This provides two key benefits:
309
+
310
+
-**Performance**: Watchers (and thereby React components) are notified only once after all operations complete, rather than after each individual operation.
311
+
-**Control**: You gain fine-grained control over optimistic updates and can intercept watcher notifications.
312
+
313
+
Here's an example that updates multiple cached items at once:
314
+
315
+
```js
316
+
cache.batch({
317
+
update(cache) {
318
+
// All these operations happen in a single batch
319
+
cache.writeQuery({
320
+
query:GET_TODOS,
321
+
data: { todos: updatedTodos },
322
+
});
323
+
324
+
cache.modify({
325
+
id:cache.identify(currentUser),
326
+
fields: {
327
+
todoCount(existing) {
328
+
return existing +1;
329
+
},
330
+
},
331
+
});
332
+
333
+
// Cleanup after the updates
334
+
cache.evict({ id:"Todo:old-item" });
335
+
},
336
+
});
337
+
```
338
+
339
+
#### Working with optimistic updates
340
+
341
+
The `optimistic` option controls how `batch` handles optimistic data:
342
+
343
+
```js
344
+
// Create a new optimistic layer with a specific ID
345
+
cache.batch({
346
+
optimistic:"add-todo-123",
347
+
update(cache) {
348
+
cache.modify({
349
+
fields: {
350
+
todos(existing= []) {
351
+
constnewTodoRef=cache.writeFragment({
352
+
data: optimisticTodo,
353
+
fragment:gql`
354
+
fragmentNewTodoonTodo {
355
+
id
356
+
text
357
+
completed
358
+
}
359
+
`,
360
+
});
361
+
return [...existing, newTodoRef];
362
+
},
363
+
},
364
+
});
365
+
},
366
+
});
367
+
368
+
// Later, remove the optimistic layer when the server responds
369
+
cache.batch({
370
+
update(cache) {
371
+
// Write the real server data
372
+
cache.writeQuery({
373
+
query:GET_TODOS,
374
+
data:serverResponse.data,
375
+
});
376
+
},
377
+
// Remove the optimistic layer in the same batch
378
+
removeOptimistic:"add-todo-123",
379
+
});
380
+
```
381
+
382
+
The `optimistic` option accepts three types of values:
Copy file name to clipboardExpand all lines: src/cache/core/cache.ts
+47-5Lines changed: 47 additions & 5 deletions
Original file line number
Diff line number
Diff line change
@@ -180,11 +180,53 @@ export abstract class ApolloCache {
180
180
181
181
// Transactional API
182
182
183
-
// The batch method is intended to replace/subsume both performTransaction
184
-
// and recordOptimisticTransaction, but performTransaction came first, so we
185
-
// provide a default batch implementation that's just another way of calling
186
-
// performTransaction. Subclasses of ApolloCache (such as InMemoryCache) can
187
-
// override the batch method to do more interesting things with its options.
183
+
/**
184
+
* Executes multiple cache operations as a single batch, ensuring that
185
+
* watchers are only notified once after all operations complete. This is
186
+
* useful for improving performance when making multiple cache updates, as it
187
+
* prevents unnecessary re-renders or query refetches between individual
188
+
* operations.
189
+
*
190
+
* The `batch` method supports both optimistic and non-optimistic updates, and
191
+
* provides fine-grained control over which cache layer receives the updates
192
+
* and when watchers are notified.
193
+
*
194
+
* For usage instructions, see [Interacting with cached data: `cache.batch`](https://www.apollographql.com/docs/react/caching/cache-interaction#using-cachebatch).
195
+
*
196
+
* @example
197
+
*
198
+
* ```js
199
+
* cache.batch({
200
+
* update(cache) {
201
+
* cache.writeQuery({
202
+
* query: GET_TODOS,
203
+
* data: { todos: updatedTodos },
204
+
* });
205
+
* cache.evict({ id: "Todo:123" });
206
+
* },
207
+
* });
208
+
* ```
209
+
*
210
+
* @example
211
+
*
212
+
* ```js
213
+
* // Optimistic update with a custom layer ID
214
+
* cache.batch({
215
+
* optimistic: "add-todo-optimistic",
216
+
* update(cache) {
217
+
* cache.modify({
218
+
* fields: {
219
+
* todos(existing = []) {
220
+
* return [...existing, newTodoRef];
221
+
* },
222
+
* },
223
+
* });
224
+
* },
225
+
* });
226
+
* ```
227
+
*
228
+
* @returns The return value of the `update` function.
// Same as the first parameter of performTransaction, except the cache
128
-
// argument will have the subclass type rather than ApolloCache.
127
+
/**
128
+
* A function that performs cache operations. Receives the cache instance as its argument.
129
+
*
130
+
* The return value of this function becomes the return value of `batch`.
131
+
*/
129
132
update(cache: TCache): TUpdateResult;
130
133
131
-
// Passing a string for this option creates a new optimistic layer, with the
132
-
// given string as its layer.id, just like passing a string for the
133
-
// optimisticId parameter of performTransaction. Passing true is the same as
134
-
// passing undefined to performTransaction (running the batch operation
135
-
// against the current top layer of the cache), and passing false is the
136
-
// same as passing null (running the operation against root/non-optimistic
137
-
// cache data).
134
+
/**
135
+
* Controls how optimistic data is handled:
136
+
*
137
+
* - `string`: Creates a new optimistic layer with this ID. Use `removeOptimistic` later to remove it.
138
+
* - `true`: Updates the current top layer of the cache (including any optimistic data).
139
+
* - `false`: Updates only the root (non-optimistic) cache data.
140
+
*
141
+
* @defaultValue false
142
+
*/
138
143
optimistic?: string|boolean;
139
144
140
-
// If you specify the ID of an optimistic layer using this option, that
141
-
// layer will be removed as part of the batch transaction, triggering at
142
-
// most one broadcast for both the transaction and the removal of the layer.
143
-
// Note: this option is needed because calling cache.removeOptimistic during
144
-
// the transaction function may not be not safe, since any modifications to
145
-
// cache layers may be discarded after the transaction finishes.
145
+
/**
146
+
* If provided, removes the optimistic layer with this ID after the batch completes.
147
+
*
148
+
* This is useful for atomically applying server data while removing a pending optimistic update, triggering at most one broadcast for both operations.
149
+
*
150
+
* Note: this option is needed because calling `cache.removeOptimistic` during the transaction function may not be safe, since any modifications to cache layers may be discarded after the transaction finishes.
151
+
*/
146
152
removeOptimistic?: string;
147
153
148
-
// If you want to find out which watched queries were invalidated during
149
-
// this batch operation, pass this optional callback function. Returning
150
-
// false from the callback will prevent broadcasting this result.
154
+
/**
155
+
* Optional callback invoked for each watcher affected by the batch operation.
156
+
*
157
+
* Receives the watch options, the new diff result, and optionally the previous diff result.
158
+
*
159
+
* Return `false` to prevent broadcasting to that specific watcher.
0 commit comments