From c832b32d7450f3be006978157f3aca7a237be027 Mon Sep 17 00:00:00 2001 From: Sebastian Sebbie Silbermann Date: Fri, 26 Sep 2025 14:50:57 +0200 Subject: [PATCH 1/4] Docs for `cacheSignal` --- src/content/reference/react/cache.md | 14 +-- src/content/reference/react/cacheSignal.md | 121 +++++++++++++++++++++ src/sidebarReference.json | 9 +- 3 files changed, 134 insertions(+), 10 deletions(-) create mode 100644 src/content/reference/react/cacheSignal.md diff --git a/src/content/reference/react/cache.md b/src/content/reference/react/cache.md index 04836f19d24..7b6984736ee 100644 --- a/src/content/reference/react/cache.md +++ b/src/content/reference/react/cache.md @@ -4,7 +4,7 @@ title: cache -`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). +`cache` is only for use with [React Server Components](/reference/rsc/server-components). @@ -62,12 +62,10 @@ The optimization of caching return values based on inputs is known as [_memoizat #### Caveats {/*caveats*/} -[//]: # 'TODO: add links to Server/Client Component reference once https://github.com/reactjs/react.dev/pull/6177 is merged' - - React will invalidate the cache for all memoized functions for each server request. - 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. - `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. -- `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. +- `cache` is for use in [Server Components](/reference/rsc/server-components) only. --- @@ -103,6 +101,8 @@ Assume `Profile` is rendered first. It will call `getUserMetr When `TeamReport` renders its list of `users` and reaches the same `user` object, it will call `getUserMetrics` and read the result from cache. +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. + ##### Calling different memoized functions will read from different caches. {/*pitfall-different-memoized-functions*/} @@ -203,8 +203,6 @@ The city acts as a cache key. -[//]: # 'TODO: add links to Server Components when merged.' - Asynchronous rendering is only supported for Server Components. ```js [[3, 1, "async"], [3, 2, "await"]] @@ -213,8 +211,8 @@ async function AnimatedWeatherCard({city}) { // ... } ``` -[//]: # 'TODO: add link and mention to use documentation when merged' -[//]: # 'To render components that use asynchronous data in Client Components, see `use` documentation.' + +To render components that use asynchronous data in Client Components, see [`use()` documentation](/reference/react/use). diff --git a/src/content/reference/react/cacheSignal.md b/src/content/reference/react/cacheSignal.md new file mode 100644 index 00000000000..d15821613ac --- /dev/null +++ b/src/content/reference/react/cacheSignal.md @@ -0,0 +1,121 @@ +--- +title: cacheSignal +--- + + + +**The `cacheSignal()` API is currently only available in React’s Canary and Experimental channels.** + +[Learn more about React’s release channels here.](/community/versioning-policy#all-release-channels) + + + + + +`cacheSignal` 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). + + + + + +`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 + +```js +const signal = cacheSignal(); +``` + + + + + +--- + +## Reference {/*reference*/} + +### `cacheSignal` {/*cachesignal*/} + +Call `cacheSignal` to get an `AbortSignal`. + +```js {3,7} +import {cacheSignal} from 'react'; +async function Component() { + await fetch(url, { signal: cacheSignal() }); +} +``` + +When React has finished rendering, the `AbortSignal` will be aborted. This allows you to cancel any in-flight work that is no longer needed. +Rendering is considered finished when: +- React has successfully completed rendering +- the render was aborted +- the render has failed + +#### Parameters {/*parameters*/} + +This function does not accept any parameters. + +#### Returns {/*returns*/} + +`cacheSignal` returns an `AbortSignal` if called during rendering. Otherwise `cacheSignal()` returns `null`. + +#### Caveats {/*caveats*/} + +- `cacheSignal` is for use in [React Server Components](/reference/rsc/server-components) only. In Client Components, it will always return `null`. +- If called outside of rendering, `cacheSignal` will return `null` to make it clear that the current scope isn't cached forever. + +--- + +## Usage {/*usage*/} + +### Cancel in-flight requests {/*cancel-in-flight-requests*/} + +Call `cacheSignal` to abort in-flight requests. + +```js [[1, 4, "cacheSignal()"]] +import {cache, cacheSignal} from 'react'; +const dedupedFetch = cache(fetch); +async function Component() { + await dedupedFetch(url, { signal: cacheSignal() }); +} +``` + + +You can't use `cacheSignal` to abort async work that was started outside of rendering e.g. + +```js +import {cacheSignal} from 'react'; +// 🚩 Pitfall: The request will not actually be aborted if the rendering of `Component` is finished. +const response = fetch(url, { signal: cacheSignal() }); +async function Component() { + await response; +} +``` + + +### Ignore errors after React has finished rendering {/*ignore-errors-after-react-has-finished-rendering*/} + +If a function throws, it may be due to cancellation (e.g. the Database connection has been closed). You can use the `aborted` property to check if the error was due to cancellation or a real error. You may want to ignore errors that were due to cancellation. + +```js [[1, 2, "./database"], [2, 8, "cacheSignal()?.aborted"], [3, 12, "return null"]] +import {cacheSignal} from "react"; +import {queryDatabase, logError} from "./database"; + +async function getData(id) { + try { + return await queryDatabase(id); + } catch (x) { + if (!cacheSignal()?.aborted) { + // only log if it's a real error and not due to cancellation + logError(x); + } + return null; + } +} + +async function Component({id}) { + const data = await getData(id); + if (data === null) { + return
No data available
; + } + return
{data.name}
; +} +``` \ No newline at end of file diff --git a/src/sidebarReference.json b/src/sidebarReference.json index 8823effb2e1..fada659aa73 100644 --- a/src/sidebarReference.json +++ b/src/sidebarReference.json @@ -128,6 +128,11 @@ "title": "cache", "path": "/reference/react/cache" }, + { + "title": "cacheSignal", + "path": "/reference/react/cacheSignal", + "version": "canary" + }, { "title": "captureOwnerStack", "path": "/reference/react/captureOwnerStack" @@ -424,7 +429,7 @@ "path": "/reference/eslint-plugin-react-hooks/lints/incompatible-library", "version": "rc" }, - + { "title": "preserve-manual-memoization", "path": "/reference/eslint-plugin-react-hooks/lints/preserve-manual-memoization", @@ -440,7 +445,7 @@ "path": "/reference/eslint-plugin-react-hooks/lints/refs", "version": "rc" }, - + { "title": "set-state-in-effect", "path": "/reference/eslint-plugin-react-hooks/lints/set-state-in-effect", From 854714a9446918136bb2a0d344c4a634bc54516a Mon Sep 17 00:00:00 2001 From: "Sebastian \"Sebbie\" Silbermann" Date: Fri, 26 Sep 2025 17:47:34 +0200 Subject: [PATCH 2/4] Apply suggestion from review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastian Markbåge --- src/content/reference/react/cacheSignal.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react/cacheSignal.md b/src/content/reference/react/cacheSignal.md index d15821613ac..7fe89f4f7e9 100644 --- a/src/content/reference/react/cacheSignal.md +++ b/src/content/reference/react/cacheSignal.md @@ -12,7 +12,7 @@ title: cacheSignal -`cacheSignal` 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). +`cacheSignal` is currently only used with [React Server Components](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components). From 14d82f6eb85081df699a8de190d109ba507fc1d6 Mon Sep 17 00:00:00 2001 From: "Sebastian \"Sebbie\" Silbermann" Date: Fri, 26 Sep 2025 17:47:43 +0200 Subject: [PATCH 3/4] Apply suggestion from review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastian Markbåge --- src/content/reference/react/cacheSignal.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react/cacheSignal.md b/src/content/reference/react/cacheSignal.md index 7fe89f4f7e9..f016630a9ea 100644 --- a/src/content/reference/react/cacheSignal.md +++ b/src/content/reference/react/cacheSignal.md @@ -59,7 +59,7 @@ This function does not accept any parameters. #### Caveats {/*caveats*/} -- `cacheSignal` is for use in [React Server Components](/reference/rsc/server-components) only. In Client Components, it will always return `null`. +- `cacheSignal` is currently for use in [React Server Components](/reference/rsc/server-components) only. In Client Components, it will always return `null`. In the future it will also be used for Client Component when a client cache refreshes or invalidates. You should not assume it'll always be null on the client. - If called outside of rendering, `cacheSignal` will return `null` to make it clear that the current scope isn't cached forever. --- From e389895a5509d1ff15b326c4a9466b1fa4d5b7ba Mon Sep 17 00:00:00 2001 From: "Sebastian \"Sebbie\" Silbermann" Date: Sun, 28 Sep 2025 17:38:12 +0200 Subject: [PATCH 4/4] Update src/content/reference/react/cacheSignal.md --- src/content/reference/react/cacheSignal.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react/cacheSignal.md b/src/content/reference/react/cacheSignal.md index f016630a9ea..31b6a34a15b 100644 --- a/src/content/reference/react/cacheSignal.md +++ b/src/content/reference/react/cacheSignal.md @@ -18,7 +18,7 @@ title: cacheSignal -`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 +`cacheSignal` allows you to know when the `cache()` life time is over. ```js const signal = cacheSignal();