|
| 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 | +``` |
0 commit comments