Skip to content

Commit

Permalink
Style edits to refetching docs (#8547)
Browse files Browse the repository at this point in the history
  • Loading branch information
Stephen Barlow authored Jul 27, 2021
1 parent 55da588 commit 7856c18
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 50 deletions.
45 changes: 18 additions & 27 deletions docs/shared/refetchQueries-options.mdx
Original file line number Diff line number Diff line change
@@ -1,15 +1,3 @@
<table class="field-table api-ref">
<thead>
<tr>
<th>Name /<br/>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>

<tr>
<td colspan="2">

The `client.refetchQueries` method take an `options` object that conforms to the
following TypeScript interface:

Expand All @@ -29,10 +17,16 @@ interface RefetchQueriesOptions<
}
```

Descriptions of these fields can be found in the table below.
These fields are described below:

</td>
</tr>
<table class="field-table api-ref">
<thead>
<tr>
<th>Name /<br/>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>

<tr>
<td>
Expand All @@ -44,8 +38,7 @@ Descriptions of these fields can be found in the table below.

<td>

Optional function that updates the cache as a way of triggering refetches of
queries whose data were affected by those cache updates.
Optional function that updates cached fields to trigger refetches of queries that include those fields.

</td>
</tr>
Expand All @@ -60,10 +53,9 @@ queries whose data were affected by those cache updates.

<td>

Optional array specifying the names or `DocumentNode` objects of queries to be
refetched.
Optional array specifying queries to refetch. Each element can be either a query's string name or a `DocumentNode` object.

Analogous to the `options.refetchQueries` array for mutations.
Analogous to the [`options.refetchQueries`](https://www.apollographql.com/docs/react/data/mutations/#options) array for mutations.

Pass `"active"` (or `"all"`) as a shorthand to refetch all (active) queries.

Expand All @@ -81,13 +73,14 @@ Pass `"active"` (or `"all"`) as a shorthand to refetch all (active) queries.

<td>

Optional callback function that will be called for each `ObservableQuery`
affected by `options.updateCache` or specified by `options.include`.
Optional callback function that's called once for each `ObservableQuery` that's either affected by `options.updateCache` or listed in `options.include` (or both).

If `onQueryUpdated` is not provided, the default implementation returns the
result of calling `observableQuery.refetch()`. When `onQueryUpdated` is
provided, it can dynamically decide whether and how each query should be
refetched. Returning `false` from `onQueryUpdated` will prevent the given query
provided, it can dynamically decide whether (and how) each query should be
refetched.

Returning `false` from `onQueryUpdated` prevents the associated query
from being refetched.

</td>
Expand All @@ -103,9 +96,7 @@ from being refetched.

<td>

If `true`, run `options.updateCache` in a temporary optimistic layer of
`InMemoryCache`, so its modifications can be discarded from the cache after
observing which fields it invalidated.
If `true`, the `options.updateCache` function is executed on a temporary optimistic layer of `InMemoryCache`, so its modifications can be discarded from the cache after observing which fields it invalidated.

Defaults to `false`, meaning `options.updateCache` updates the cache in a
lasting way.
Expand Down
105 changes: 82 additions & 23 deletions docs/source/data/refetching.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,84 @@ sidebar_title: Refetching

import RefetchQueriesOptions from '../../shared/refetchQueries-options.mdx';

Although Apollo Client allows you to make local modifications to previously received GraphQL data by updating the cache, sometimes the easiest way to update your client-side GraphQL data is to _refetch_ it from the server.
Apollo Client allows you to make local modifications to your GraphQL data by [updating the cache](./mutations/#updating-the-cache-directly), but sometimes it's more straightforward to update your client-side GraphQL data by refetching queries from the server.

In principle, you could refetch every active query after any client-side update, but you can save time and network bandwidth by refetching queries more selectively, taking advantage of `InMemoryCache` to determine which watched queries may have been invalidated by recent cache updates.
In theory, you could refetch _every_ active query after a client-side update, but you can save time and network bandwidth by refetching queries more selectively. The `InMemoryCache` helps you determine _which_ active queries might have been invalidated by recent cache updates.

These two approaches (local updates and refetching) work well together: if your application displays the results of local cache modifications immediately, you can use refetching in the background to obtain the very latest data from the server, rerendering the UI only if there are differences between local data and refetched data.
Local cache updates and refetching work especially well in combination: your application can display the results of local cache modifications immediately, while _also_ refetching in the background to obtain the very latest data from the server. The UI is then rerendered only if there are differences between local data and refetched data.

Refetching is especially common after a mutation, so `client.mutate` accepts options like `refetchQueries` and `onQueryUpdated` to specify which queries should be refetched, and how. However, the tools of selective refetching are available even if you are not performing a mutation, in the form of the `client.refetchQueries` method.
Refetching is especially common after a mutation, so [mutate functions](./mutations/#executing-a-mutation) accept options like [`refetchQueries`](./mutations/#refetching-queries) and [`onQueryUpdated`](./mutations/#refetching-after-update) to specify which queries should be refetched, and how.

To selectively refetch queries _outside_ of a mutation, you instead use the `refetchQueries` method of `ApolloClient`, which is documented here.

## `client.refetchQueries`

> This method is new in Apollo Client 3.4.
### Refetch options

<RefetchQueriesOptions />

### Refetch results

The `client.refetchQueries` method collects the `TResult` results returned by `onQueryUpdated`, defaulting to `TResult = Promise<ApolloQueryResult<any>>` if `onQueryUpdated` is not provided, and combines the results into a single `Promise<TResolved[]>` using `Promise.all(results)`.
The `client.refetchQueries` method collects the `TResult` results returned by `onQueryUpdated`, defaulting to `TResult = Promise<ApolloQueryResult<any>>` if `onQueryUpdated` is not provided. It combines those results into a single `Promise<TResolved[]>` using `Promise.all(results)`.

> Thanks to the `Promise`-unwrapping behavior of `Promise.all`, this `TResolved` type will often be the same type as `TResult`, except when `TResult` is a `PromiseLike<TResolved>` or a `boolean`.
> Thanks to the `Promise`-unwrapping behavior of `Promise.all`, this `TResolved` type is often the same type as `TResult`, except when `TResult` is a `PromiseLike<TResolved>` or a `boolean`.
The returned `Promise` object has two other useful properties:

| Property | Type | Description |
| - | - | - |
| `queries` | `ObservableQuery[]` | An array of `ObservableQuery` objects that were refetched |
| `results` | `TResult[]` | An array of results that were either returned by `onQueryUpdated`, or provided by default in the absence of `onQueryUpdated`, including pending promises. If `onQueryUpdated` returns `false` for a given query, no result will be provided for that query. If `onQueryUpdated` returns `true`, the resulting `Promise<ApolloQueryResult<any>>` will be included in the `results` array, rather than `true`. |
<table class="field-table api-ref">
<thead>
<tr>
<th>Name /<br/>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>

<tr>
<td>

###### `queries`

`ObservableQuery[]`
</td>

<td>

An array of `ObservableQuery` objects that were refetched.

</td>
</tr>

<tr>
<td>

###### `results`

`TResult[]`
</td>

<td>

An array of results that were either returned by `onQueryUpdated`, or provided by default in the absence of `onQueryUpdated`, including pending promises.

If `onQueryUpdated` returns `false` for a given query, no result is provided for that query.

If `onQueryUpdated` returns `true`, the resulting `Promise<ApolloQueryResult<any>>` is included in the `results` array instead of `true`.

</td>
</tr>

</tbody>
</table>

These two arrays parallel each other: they have the same length, and `results[i]` is the result produced by `onQueryUpdated` when called with the `ObservableQuery` found at `queries[i]`, for any index `i`.

### Refetch recipes

#### Refetching a specific query

To refetch a specific query by name, use the `include` option by itself:

```ts
Expand All @@ -52,22 +99,26 @@ await client.refetchQueries({
});
```

To refetch all active queries, pass the `"active"` shorthand for `include`:
#### Refetching all queries

To refetch all _active_ queries, pass the `"active"` shorthand for `include`:
```ts
await client.refetchQueries({
include: "active",
});
```

To refetch _all_ queries managed by Apollo Client, even those with no observers, or whose components are currently unmounted, pass `"all"` for `include`:
To refetch _all_ queries managed by Apollo Client (even those with no observers, or whose components are currently unmounted), pass `"all"` for `include`:

```ts
await client.refetchQueries({
include: "all", // Consider using "active" instead!
});
```

Alternatively, you can refetch queries affected by cache updates performed in the `updateCache` callback:
#### Refetching queries affected by cache updates

You can refetch queries affected by cache updates performed in the `updateCache` callback:

```ts
await client.refetchQueries({
Expand All @@ -77,7 +128,9 @@ await client.refetchQueries({
});
```

This will refetch any queries that depend on `Query.someRootField`, without requiring you to know in advance which queries might be included. Any combination of cache operations (`writeQuery`, `writeFragment`, `modify`, `evict`, etc.) is allowed within `updateCache`. Updates performed by `updateCache` persist in the cache by default, but you can choose to perform them in a temporary optimistic layer instead, if you want them to be discarded immediately after `client.refetchQueries` is done observing them, leaving the cache unchanged:
This refetches any queries that depend on `Query.someRootField`, without requiring you to know in advance which queries might be included. Any combination of cache operations (`writeQuery`, `writeFragment`, `modify`, `evict`, etc.) is allowed within `updateCache`.

Updates performed by `updateCache` persist in the cache by default. You can perform them in a temporary optimistic layer instead, if you want them to be discarded immediately after `client.refetchQueries` is done observing them, leaving the cache unchanged:

```ts
await client.refetchQueries({
Expand All @@ -90,7 +143,7 @@ await client.refetchQueries({
});
```

Another way of updating the cache without changing cache data is to use `cache.modify` and its `INVALIDATE` sentinel object:
Another way to "update" the cache without actually changing cache data is to use `cache.modify` and its `INVALIDATE` sentinel object:

```ts
await client.refetchQueries({
Expand All @@ -108,11 +161,15 @@ await client.refetchQueries({
});
```

> Before `client.refetchQueries` was introduced, the `INVALIDATE` sentinel was [not very useful](https://github.com/apollographql/apollo-client/issues/7060#issuecomment-698026089), since invalidated queries with `fetchPolicy: "cache-first"` would typically re-read unchanged results, and therefore decide not to perform a network request. The `client.refetchQueries` method makes this invalidation system more accessible to application code, so you can control the refetching behavior of invalidated queries.
> Before `client.refetchQueries` was introduced, the `INVALIDATE` sentinel was [not very useful](https://github.com/apollographql/apollo-client/issues/7060#issuecomment-698026089), because invalidated queries with `fetchPolicy: "cache-first"` would typically re-read unchanged results, and therefore decide not to perform a network request. The `client.refetchQueries` method makes this invalidation system more accessible to application code, so you can control the refetching behavior of invalidated queries.
In all of the examples above, whether we use `include` or `updateCache`, `client.refetchQueries` will refetch the affected queries from the network and include the resulting `Promise<ApolloQueryResult<any>>` results in the `Promise<TResolved[]>` returned by `client.refetchQueries`. If a single query happens to be included both by `include` and by `updateCache`, that query will be refetched only once. In other words, the `include` option is a good way to make sure certain queries are always included, no matter which queries are included by `updateCache`.
In all of the examples above, whether we use `include` or `updateCache`, `client.refetchQueries` refetches affected queries from the network and includes the resulting `Promise<ApolloQueryResult<any>>` results in the `Promise<TResolved[]>` returned by `client.refetchQueries`.

In development, you will probably want to make sure the appropriate queries are getting refetched, rather than blindly refetching them. To intercept each query before refetching, you can specify an `onQueryUpdated` callback:
If a particular query is included both by `include` and by `updateCache`, that query is refetched only once. In other words, the `include` option is a good way to make sure certain queries are always included, no matter which queries are included by `updateCache`.

#### Refetching selectively

In development, you probably want to make sure the appropriate queries are getting refetched, rather than blindly refetching them. To intercept each query before refetching, you can specify an `onQueryUpdated` callback:

```ts
const results = await client.refetchQueries({
Expand Down Expand Up @@ -205,7 +262,9 @@ await client.refetchQueries({
});
```

In the examples above we `await client.refetchQueries(...)` to find out the final `ApolloQueryResult<any>` results for all the refetched queries. This combined promise is created with `Promise.all`, so a single failure will reject the entire `Promise<TResolved[]>`, potentially hiding other successful results. If this is a problem, you can use the `queries` and `results` arrays returned by
#### Handling refetch errors

In the examples above, we `await client.refetchQueries(...)` to find out the final `ApolloQueryResult<any>` results for all the refetched queries. This combined promise is created with `Promise.all`, so a single failure rejects the entire `Promise<TResolved[]>`, potentially hiding other successful results. If this is a problem, you can use the `queries` and `results` arrays returned by
`client.refetchQueries` instead of (or in addition to) `await`ing the `Promise`:

```ts
Expand All @@ -227,15 +286,15 @@ In the future, just as additional input options may be added to the `client.refe

If you discover that some specific additional `client.refetchQueries` input options or result properties would be useful, please feel free to [open an issue](https://github.com/apollographql/apollo-feature-requests/issues) or [start a discussion](https://github.com/apollographql/apollo-client/discussions) explaining your use case(s).

### Relationship to `client.mutate` options
### Corresponding `client.mutate` options

For refetching after a mutation, the `client.mutate` method supports options similar to `client.refetchQueries`, which you should use instead of `client.refetchQueries`, because it's important for refetching logic to happen at specific times during the mutation process.
For refetching after a mutation, `client.mutate` supports [options](./mutations/#options) similar to `client.refetchQueries`, which you should use instead of `client.refetchQueries`, because it's important for refetching logic to happen at specific times during the mutation process.

For historical reasons, the `client.mutate` options have slightly different names from the new `client.refetchQueries` options, but their internal implementation is substantially the same, so you can translate between them using the following table:
For historical reasons, `client.mutate` options have slightly different names from the new `client.refetchQueries` options, but their internal implementation is substantially the same, so you can translate between them using the following table:

| `client.mutate(options)` | | `client.refetchQueries(options)` |
| - | - | - |
| [`options.refetchQueries`](./mutations/#refetching-queries) || `options.include` |
| [`options.update`](./mutations/#the-update-function) || `options.updateCache` |
| [`options.onQueryUpdated`](./mutations/#refetching-after-update) || `options.onQueryUpdated` |
| [`options.awaitRefetchQueries`](./mutations/#options) || just return a `Promise` from `onQueryUpdated` |
| [`options.awaitRefetchQueries`](./mutations/#options) || Return a `Promise` from `onQueryUpdated` |

0 comments on commit 7856c18

Please sign in to comment.