Skip to content

Commit 039174b

Browse files
committed
Docs for cacheSignal
1 parent 790625f commit 039174b

File tree

4 files changed

+135
-11
lines changed

4 files changed

+135
-11
lines changed

src/components/MDX/ExpandableCallout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ const variantMap = {
103103
'linear-gradient(rgba(249, 247, 243, 0), rgba(249, 247, 243, 1)',
104104
},
105105
rsc: {
106-
title: 'React Server Components',
106+
title: 'Server Components',
107107
Icon: null,
108108
containerClasses: 'bg-blue-10 dark:bg-blue-60 dark:bg-opacity-20',
109109
textColor: 'text-blue-50 dark:text-blue-40',

src/content/reference/react/cache.md

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ title: cache
44

55
<RSC>
66

7-
`cache` is only for use with [React Server Components](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components).
7+
`cache` is only for use with [Server Components](/reference/rsc/server-components).
88

99
</RSC>
1010

@@ -62,12 +62,10 @@ The optimization of caching return values based on inputs is known as [_memoizat
6262

6363
#### Caveats {/*caveats*/}
6464

65-
[//]: # 'TODO: add links to Server/Client Component reference once https://github.com/reactjs/react.dev/pull/6177 is merged'
66-
6765
- React will invalidate the cache for all memoized functions for each server request.
6866
- Each call to `cache` creates a new function. This means that calling `cache` with the same function multiple times will return different memoized functions that do not share the same cache.
6967
- `cachedFn` will also cache errors. If `fn` throws an error for certain arguments, it will be cached, and the same error is re-thrown when `cachedFn` is called with those same arguments.
70-
- `cache` is for use in [Server Components](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components) only.
68+
- `cache` is for use in [Server Components](/reference/rsc/server-components) only.
7169

7270
---
7371

@@ -103,6 +101,8 @@ Assume `Profile` is rendered first. It will call <CodeStep step={1}>`getUserMetr
103101

104102
When `TeamReport` renders its list of `users` and reaches the same `user` object, it will call <CodeStep step={2}>`getUserMetrics`</CodeStep> and read the result from cache.
105103

104+
If `calculateUserMetrics` can be aborted by passing an [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal), you can use [`cacheSignal()`](/reference/react/cacheSignal) to cancel the expensive computation if React has finished rendering. `calculateUserMetrics` may already handle cancellation internally by using `cacheSignal` directly.
105+
106106
<Pitfall>
107107

108108
##### Calling different memoized functions will read from different caches. {/*pitfall-different-memoized-functions*/}
@@ -203,8 +203,6 @@ The <CodeStep step={1}>city</CodeStep> acts as a cache key.
203203

204204
<Note>
205205

206-
[//]: # 'TODO: add links to Server Components when merged.'
207-
208206
<CodeStep step={3}>Asynchronous rendering</CodeStep> is only supported for Server Components.
209207

210208
```js [[3, 1, "async"], [3, 2, "await"]]
@@ -213,8 +211,8 @@ async function AnimatedWeatherCard({city}) {
213211
// ...
214212
}
215213
```
216-
[//]: # 'TODO: add link and mention to use documentation when merged'
217-
[//]: # 'To render components that use asynchronous data in Client Components, see `use` documentation.'
214+
215+
To render components that use asynchronous data in Client Components, see [`use()` documentation](/reference/react/use).
218216

219217
</Note>
220218

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
---
2+
title: cacheSignal
3+
---
4+
5+
<Canary>
6+
7+
**The `cacheSignal()` API is currently only available in React’s Canary and Experimental channels.**
8+
9+
[Learn more about React’s release channels here.](/community/versioning-policy#all-release-channels)
10+
11+
</Canary>
12+
13+
<RSC>
14+
15+
`cacheSignal` is only for use with [Server Components](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components).
16+
17+
</RSC>
18+
19+
<Intro>
20+
21+
`cacheSignal()` returns an [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) which aborts when the cache lifetime is done based on the same execution scope as a [`cache()`](/reference/react/cache)ed function
22+
23+
```js
24+
const signal = cacheSignal();
25+
```
26+
27+
</Intro>
28+
29+
<InlineToc />
30+
31+
---
32+
33+
## Reference {/*reference*/}
34+
35+
### `cacheSignal` {/*cachesignal*/}
36+
37+
Call `cacheSignal` to get an `AbortSignal`.
38+
39+
```js {3,7}
40+
import {cacheSignal} from 'react';
41+
async function Component() {
42+
await fetch(url, { signal: cacheSignal() });
43+
}
44+
```
45+
46+
When React has finished rendering, the `AbortSignal` will be aborted. This allows you to cancel any in-flight work that is no longer needed.
47+
Rendering is considered finished when:
48+
- React has successfully completed rendering
49+
- the render was aborted
50+
- the render has failed
51+
52+
#### Parameters {/*parameters*/}
53+
54+
This function does not accept any parameters.
55+
56+
#### Returns {/*returns*/}
57+
58+
`cacheSignal` returns an `AbortSignal` if called during rendering. Otherwise `cacheSignal()` returns `null`.
59+
60+
#### Caveats {/*caveats*/}
61+
62+
- `cacheSignal` is for use in [Server Components](/reference/rsc/server-components) only. In Client Components, it will always return `null`.
63+
- If called outside of rendering, `cacheSignal` will return `null` to make it clear that the current scope isn't cached forever.
64+
65+
---
66+
67+
## Usage {/*usage*/}
68+
69+
### Cancel in-flight requests {/*cancel-in-flight-requests*/}
70+
71+
Call <CodeStep step={1}>`cacheSignal`</CodeStep> to abort in-flight requests.
72+
73+
```js [[1, 4, "cacheSignal()"]]
74+
import {cache, cacheSignal} from 'react';
75+
const dedupedFetch = cache(fetch);
76+
async function Component() {
77+
await dedupedFetch(url, { signal: cacheSignal() });
78+
}
79+
```
80+
81+
<Pitfall>
82+
You can't use `cacheSignal` to abort async work that was started outside of rendering e.g.
83+
84+
```js
85+
import {cacheSignal} from 'react';
86+
// 🚩 Pitfall: The request will not actually be aborted if the rendering of `Component` is finished.
87+
const response = fetch(url, { signal: cacheSignal() });
88+
async function Component() {
89+
await response;
90+
}
91+
```
92+
</Pitfall>
93+
94+
### Ignore errors after React has finished rendering {/*ignore-errors-after-react-has-finished-rendering*/}
95+
96+
If a function throws, it may be due to cancellation (e.g. <CodeStep step={1}>the Database connection</CodeStep> has been closed). You can use the <CodeStep step={2}>`aborted` property</CodeStep> to check if the error was due to cancellation or a real error. You may want to <CodeStep step={3}>ignore errors</CodeStep> that were due to cancellation.
97+
98+
```js [[1, 2, "./database"], [2, 8, "cacheSignal()?.aborted"], [3, 12, "return null"]]
99+
import {cacheSignal} from "react";
100+
import {queryDatabase, logError} from "./database";
101+
102+
async function getData(id) {
103+
try {
104+
return await queryDatabase(id);
105+
} catch (x) {
106+
if (!cacheSignal()?.aborted) {
107+
// only log if it's a real error and not due to cancellation
108+
logError(x);
109+
}
110+
return null;
111+
}
112+
}
113+
114+
async function Component({id}) {
115+
const data = await getData(id);
116+
if (data === null) {
117+
return <div>No data available</div>;
118+
}
119+
return <div>{data.name}</div>;
120+
}
121+
```

src/sidebarReference.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,11 @@
128128
"title": "cache",
129129
"path": "/reference/react/cache"
130130
},
131+
{
132+
"title": "cacheSignal",
133+
"path": "/reference/react/cacheSignal",
134+
"version": "canary"
135+
},
131136
{
132137
"title": "captureOwnerStack",
133138
"path": "/reference/react/captureOwnerStack"
@@ -424,7 +429,7 @@
424429
"path": "/reference/eslint-plugin-react-hooks/lints/incompatible-library",
425430
"version": "rc"
426431
},
427-
432+
428433
{
429434
"title": "preserve-manual-memoization",
430435
"path": "/reference/eslint-plugin-react-hooks/lints/preserve-manual-memoization",
@@ -440,7 +445,7 @@
440445
"path": "/reference/eslint-plugin-react-hooks/lints/refs",
441446
"version": "rc"
442447
},
443-
448+
444449
{
445450
"title": "set-state-in-effect",
446451
"path": "/reference/eslint-plugin-react-hooks/lints/set-state-in-effect",

0 commit comments

Comments
 (0)