Skip to content

Conversation

@sebmarkbage
Copy link
Collaborator

@sebmarkbage sebmarkbage commented Jun 17, 2025

This was really meant to be there from the beginning. A cache():ed entry has a life time. On the server this ends when the render finishes. On the client this ends when the cache of that scope gets refreshed.

When a cache is no longer needed, it should be possible to abort any outstanding network requests or other resources. That's what cacheSignal() gives you. It returns an AbortSignal which aborts when the cache lifetime is done based on the same execution scope as a cache()ed function - i.e. AsyncLocalStorage on the server or the render scope on the client.

import {cacheSignal} from 'react'; async function Component() { await fetch(url, { signal: cacheSignal() }); }

For fetch in particular, a patch should really just do this automatically for you. But it's useful for other resources like database connections.

Another reason it's useful to have a cacheSignal() is to ignore any errors that might have triggered from the act of being aborted. This is just a general useful JavaScript pattern if you have access to a signal:

async function getData(id, signal) { try { await queryDatabase(id, { signal }); } catch (x) { if (!signal.aborted) { logError(x); // only log if it's a real error and not due to cancellation } return null; } }

This just gets you a convenient way to get to it without drilling through so a more idiomatic code in React might look something like.

import {cacheSignal} from "react"; async function getData(id) { try { await queryDatabase(id); } catch (x) { if (!cacheSignal()?.aborted) { logError(x); } return null; } }

If it's called outside of a React render, we normally treat any cached functions as uncached. They're not an error call. They can still load data. It's just not cached. This is not like an aborted signal because then you couldn't issue any requests. It's also not like an infinite abort signal because it's not actually cached forever. Therefore, cacheSignal() returns null when called outside of a React render scope.

Notably the signal option passed to renderToReadableStream in both SSR (Fizz) and RSC (Flight Server) is not the same instance that comes out of cacheSignal(). If you abort the signal passed in, then the cacheSignal() is also aborted with the same reason. However, the cacheSignal() can also get aborted if the render completes successfully or fatally errors during render - allowing any outstanding work that wasn't used to clean up. In the future we might also expand on this to give different TaskSignal to different scopes to pass different render or network priorities.

On the client version of "react" this exposes a noop (both for Fiber/Fizz) due to disableClientCache flag but it's exposed so that you can write shared code.

This is exposed every but is a noop on the client by disableClientCache flag just like its cache() sibling.
This was already implemented but never exposed.
Notably this is currently always creating a new signal rather than passing the one you pass into the Web Streams APIs. It might be better ot pass the original one through so that it can contain other information such as TaskSignal to handle priorities. However, I'm not sure if we'd want to wrap it with our own TaskSignal yet.
@github-actions github-actions bot added the React Core Team Opened by a member of the React Core Team label Jun 17, 2025
@sebmarkbage sebmarkbage changed the title Expose cacheSignal() along side cache() Expose cacheSignal() alongside cache() Jun 17, 2025
@react-sizebot
Copy link

Comparing: 90bee81...f7d041a

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable/react-dom/cjs/react-dom.production.js = 6.68 kB 6.68 kB = 1.83 kB 1.83 kB
oss-stable/react-dom/cjs/react-dom-client.production.js +0.02% 530.47 kB 530.57 kB +0.03% 93.64 kB 93.67 kB
oss-experimental/react-dom/cjs/react-dom.production.js = 6.69 kB 6.69 kB = 1.83 kB 1.83 kB
oss-experimental/react-dom/cjs/react-dom-client.production.js +0.01% 651.56 kB 651.66 kB +0.03% 114.75 kB 114.78 kB
facebook-www/ReactDOM-prod.classic.js +0.01% 674.72 kB 674.81 kB +0.02% 118.75 kB 118.78 kB
facebook-www/ReactDOM-prod.modern.js +0.01% 665.20 kB 665.30 kB +0.02% 117.17 kB 117.19 kB
oss-experimental/react-noop-renderer/cjs/react-noop-renderer-flight-server.production.js +18.80% 2.09 kB 2.48 kB +13.95% 0.72 kB 0.82 kB
oss-stable-semver/react-noop-renderer/cjs/react-noop-renderer-flight-server.production.js +18.80% 2.09 kB 2.48 kB +13.95% 0.72 kB 0.82 kB
oss-stable/react-noop-renderer/cjs/react-noop-renderer-flight-server.production.js +18.80% 2.09 kB 2.48 kB +13.95% 0.72 kB 0.82 kB
oss-experimental/react-noop-renderer/cjs/react-noop-renderer-flight-server.development.js +17.61% 2.45 kB 2.89 kB +12.55% 0.80 kB 0.90 kB
oss-stable-semver/react-noop-renderer/cjs/react-noop-renderer-flight-server.development.js +17.61% 2.45 kB 2.89 kB +12.55% 0.80 kB 0.90 kB
oss-stable/react-noop-renderer/cjs/react-noop-renderer-flight-server.development.js +17.61% 2.45 kB 2.89 kB +12.55% 0.80 kB 0.90 kB
oss-experimental/react-suspense-test-utils/cjs/react-suspense-test-utils.js +4.26% 1.22 kB 1.27 kB +2.01% 0.60 kB 0.61 kB
oss-stable-semver/react-suspense-test-utils/cjs/react-suspense-test-utils.js +4.26% 1.22 kB 1.27 kB +2.01% 0.60 kB 0.61 kB
oss-stable/react-suspense-test-utils/cjs/react-suspense-test-utils.js +4.26% 1.22 kB 1.27 kB +2.01% 0.60 kB 0.61 kB

Significant size changes

Includes any change greater than 0.2%:

Expand to show
Name +/- Base Current +/- gzip Base gzip Current gzip
oss-experimental/react-noop-renderer/cjs/react-noop-renderer-flight-server.production.js +18.80% 2.09 kB 2.48 kB +13.95% 0.72 kB 0.82 kB
oss-stable-semver/react-noop-renderer/cjs/react-noop-renderer-flight-server.production.js +18.80% 2.09 kB 2.48 kB +13.95% 0.72 kB 0.82 kB
oss-stable/react-noop-renderer/cjs/react-noop-renderer-flight-server.production.js +18.80% 2.09 kB 2.48 kB +13.95% 0.72 kB 0.82 kB
oss-experimental/react-noop-renderer/cjs/react-noop-renderer-flight-server.development.js +17.61% 2.45 kB 2.89 kB +12.55% 0.80 kB 0.90 kB
oss-stable-semver/react-noop-renderer/cjs/react-noop-renderer-flight-server.development.js +17.61% 2.45 kB 2.89 kB +12.55% 0.80 kB 0.90 kB
oss-stable/react-noop-renderer/cjs/react-noop-renderer-flight-server.development.js +17.61% 2.45 kB 2.89 kB +12.55% 0.80 kB 0.90 kB
oss-experimental/react-suspense-test-utils/cjs/react-suspense-test-utils.js +4.26% 1.22 kB 1.27 kB +2.01% 0.60 kB 0.61 kB
oss-stable-semver/react-suspense-test-utils/cjs/react-suspense-test-utils.js +4.26% 1.22 kB 1.27 kB +2.01% 0.60 kB 0.61 kB
oss-stable/react-suspense-test-utils/cjs/react-suspense-test-utils.js +4.26% 1.22 kB 1.27 kB +2.01% 0.60 kB 0.61 kB
oss-stable-semver/react-server/cjs/react-server-flight.production.js +1.04% 58.69 kB 59.30 kB +1.50% 11.76 kB 11.94 kB
oss-stable/react-server/cjs/react-server-flight.production.js +1.04% 58.69 kB 59.30 kB +1.50% 11.76 kB 11.94 kB
oss-stable-semver/react/cjs/react.react-server.production.js +1.03% 13.31 kB 13.45 kB +0.74% 3.67 kB 3.70 kB
oss-stable/react/cjs/react.react-server.production.js +1.03% 13.33 kB 13.47 kB +0.65% 3.70 kB 3.72 kB
oss-experimental/react-server/cjs/react-server-flight.production.js +0.94% 63.70 kB 64.30 kB +1.41% 12.66 kB 12.84 kB
oss-experimental/react/cjs/react.react-server.production.js +0.73% 18.89 kB 19.03 kB +0.44% 4.99 kB 5.02 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-server.browser.production.js +0.69% 87.11 kB 87.71 kB +0.97% 18.13 kB 18.30 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-server.browser.production.js +0.69% 87.11 kB 87.71 kB +0.97% 18.13 kB 18.30 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-server.edge.production.js +0.65% 88.33 kB 88.91 kB +0.96% 18.38 kB 18.56 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-server.edge.production.js +0.65% 88.33 kB 88.91 kB +0.96% 18.38 kB 18.56 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-server.browser.production.js +0.64% 91.71 kB 92.30 kB +0.98% 18.88 kB 19.07 kB
oss-stable-semver/react-server-dom-esm/cjs/react-server-dom-esm-server.node.production.js +0.64% 90.58 kB 91.15 kB +0.93% 18.86 kB 19.04 kB
oss-stable/react-server-dom-esm/cjs/react-server-dom-esm-server.node.production.js +0.64% 90.58 kB 91.15 kB +0.93% 18.86 kB 19.04 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.browser.production.js +0.64% 94.11 kB 94.71 kB +0.94% 19.23 kB 19.41 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.browser.production.js +0.64% 94.11 kB 94.71 kB +0.94% 19.23 kB 19.41 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.production.js +0.63% 94.52 kB 95.12 kB +0.94% 19.33 kB 19.52 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.production.js +0.63% 94.52 kB 95.12 kB +0.94% 19.33 kB 19.52 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-server.edge.production.js +0.61% 93.02 kB 93.59 kB +0.93% 19.16 kB 19.34 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-server.node.production.js +0.61% 94.55 kB 95.12 kB +0.87% 19.34 kB 19.51 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-server.node.production.js +0.61% 94.55 kB 95.12 kB +0.87% 19.34 kB 19.51 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.production.js +0.61% 95.33 kB 95.91 kB +0.92% 19.51 kB 19.69 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.production.js +0.61% 95.33 kB 95.91 kB +0.92% 19.51 kB 19.69 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.edge.production.js +0.61% 95.35 kB 95.92 kB +0.91% 19.50 kB 19.68 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.edge.production.js +0.61% 95.35 kB 95.92 kB +0.91% 19.50 kB 19.68 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.browser.production.js +0.60% 98.71 kB 99.30 kB +0.94% 20.07 kB 20.26 kB
oss-experimental/react-server-dom-esm/cjs/react-server-dom-esm-server.node.production.js +0.60% 95.13 kB 95.70 kB +0.98% 19.62 kB 19.82 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.production.js +0.60% 99.12 kB 99.72 kB +0.91% 20.17 kB 20.36 kB
oss-stable-semver/react-server/cjs/react-server-flight.development.js +0.58% 110.12 kB 110.75 kB +0.87% 20.34 kB 20.52 kB
oss-stable/react-server/cjs/react-server-flight.development.js +0.58% 110.12 kB 110.75 kB +0.87% 20.34 kB 20.52 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-server.node.production.js +0.57% 99.10 kB 99.67 kB +0.92% 20.10 kB 20.29 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.unbundled.production.js +0.57% 100.62 kB 101.20 kB +0.88% 20.30 kB 20.48 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.unbundled.production.js +0.57% 100.62 kB 101.20 kB +0.88% 20.30 kB 20.48 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.production.js +0.57% 100.02 kB 100.59 kB +0.89% 20.39 kB 20.57 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.edge.production.js +0.57% 100.04 kB 100.60 kB +0.89% 20.38 kB 20.56 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.node.production.js +0.57% 101.63 kB 102.21 kB +0.87% 20.51 kB 20.68 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.node.production.js +0.57% 101.63 kB 102.21 kB +0.87% 20.51 kB 20.68 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.production.js +0.57% 101.68 kB 102.25 kB +0.89% 20.52 kB 20.70 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.production.js +0.57% 101.68 kB 102.25 kB +0.89% 20.52 kB 20.70 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.unbundled.production.js +0.54% 105.18 kB 105.75 kB +0.94% 21.07 kB 21.27 kB
oss-experimental/react-server/cjs/react-server-flight.development.js +0.54% 118.00 kB 118.63 kB +0.83% 21.76 kB 21.94 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.node.production.js +0.54% 106.19 kB 106.76 kB +0.88% 21.36 kB 21.54 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.production.js +0.54% 106.23 kB 106.80 kB +0.88% 21.37 kB 21.55 kB
oss-stable-semver/react/cjs/react.react-server.development.js +0.53% 28.70 kB 28.85 kB +0.32% 6.95 kB 6.97 kB
oss-stable/react/cjs/react.react-server.development.js +0.53% 28.72 kB 28.87 kB +0.32% 6.97 kB 6.99 kB
oss-experimental/react/cjs/react.react-server.development.js +0.42% 36.51 kB 36.66 kB +0.25% 8.68 kB 8.70 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-server.edge.development.js +0.42% 152.63 kB 153.26 kB +0.64% 28.09 kB 28.27 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-server.edge.development.js +0.42% 152.63 kB 153.26 kB +0.64% 28.09 kB 28.27 kB
oss-stable-semver/react-server-dom-esm/cjs/react-server-dom-esm-server.node.development.js +0.41% 153.42 kB 154.06 kB +0.63% 28.46 kB 28.64 kB
oss-stable/react-server-dom-esm/cjs/react-server-dom-esm-server.node.development.js +0.41% 153.42 kB 154.06 kB +0.63% 28.46 kB 28.64 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-server.node.development.js +0.40% 158.09 kB 158.72 kB +0.61% 28.92 kB 29.09 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-server.node.development.js +0.40% 158.09 kB 158.72 kB +0.61% 28.92 kB 29.09 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.development.js +0.40% 160.47 kB 161.11 kB +0.62% 29.46 kB 29.65 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.development.js +0.40% 160.47 kB 161.11 kB +0.62% 29.46 kB 29.65 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.edge.development.js +0.40% 160.50 kB 161.13 kB +0.61% 29.46 kB 29.64 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.edge.development.js +0.40% 160.50 kB 161.13 kB +0.61% 29.46 kB 29.64 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-server.edge.development.js +0.39% 160.87 kB 161.51 kB +0.68% 29.52 kB 29.72 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.unbundled.development.js +0.39% 164.93 kB 165.56 kB +0.58% 29.99 kB 30.16 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.unbundled.development.js +0.39% 164.93 kB 165.56 kB +0.58% 29.99 kB 30.16 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.node.development.js +0.38% 166.08 kB 166.71 kB +0.57% 30.26 kB 30.44 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.node.development.js +0.38% 166.08 kB 166.71 kB +0.57% 30.26 kB 30.44 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.development.js +0.38% 166.13 kB 166.77 kB +0.57% 30.28 kB 30.45 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.development.js +0.38% 166.13 kB 166.77 kB +0.57% 30.28 kB 30.45 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.development.js +0.38% 168.72 kB 169.35 kB +0.62% 30.93 kB 31.12 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.edge.development.js +0.38% 168.75 kB 169.38 kB +0.62% 30.92 kB 31.12 kB
oss-experimental/react-server-dom-esm/cjs/react-server-dom-esm-server.node.development.js +0.36% 172.56 kB 173.18 kB +0.68% 32.01 kB 32.23 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-server.node.development.js +0.35% 177.22 kB 177.85 kB +0.65% 32.48 kB 32.69 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.unbundled.development.js +0.34% 184.06 kB 184.69 kB +0.65% 33.55 kB 33.77 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.node.development.js +0.34% 185.21 kB 185.84 kB +0.64% 33.84 kB 34.06 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.development.js +0.34% 185.26 kB 185.89 kB +0.66% 33.85 kB 34.07 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-server.browser.development.js +0.34% 149.06 kB 149.56 kB +0.71% 27.59 kB 27.78 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-server.browser.development.js +0.34% 149.06 kB 149.56 kB +0.71% 27.59 kB 27.78 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.browser.development.js +0.32% 156.89 kB 157.40 kB +0.65% 28.97 kB 29.16 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.browser.development.js +0.32% 156.89 kB 157.40 kB +0.65% 28.97 kB 29.16 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-server.browser.development.js +0.32% 156.95 kB 157.46 kB +0.67% 29.00 kB 29.19 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.development.js +0.32% 157.44 kB 157.94 kB +0.64% 29.09 kB 29.28 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.development.js +0.32% 157.44 kB 157.94 kB +0.64% 29.09 kB 29.28 kB
oss-stable-semver/react/cjs/react.production.js +0.32% 16.99 kB 17.05 kB +0.25% 4.39 kB 4.41 kB
oss-stable/react/cjs/react.production.js +0.32% 17.02 kB 17.07 kB +0.23% 4.42 kB 4.43 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.browser.development.js +0.31% 164.79 kB 165.29 kB +0.69% 30.36 kB 30.57 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.development.js +0.30% 165.33 kB 165.84 kB +0.69% 30.48 kB 30.69 kB
facebook-react-native/react/cjs/React-prod.js +0.28% 19.09 kB 19.15 kB +0.22% 4.95 kB 4.96 kB
oss-experimental/react/cjs/react.production.js +0.28% 19.36 kB 19.42 kB +0.24% 4.93 kB 4.94 kB
facebook-react-native/react/cjs/React-profiling.js +0.28% 19.53 kB 19.58 kB +0.22% 5.03 kB 5.04 kB
facebook-www/React-prod.modern.js +0.26% 20.67 kB 20.73 kB +0.23% 5.31 kB 5.32 kB
facebook-www/React-prod.classic.js +0.26% 20.68 kB 20.73 kB +0.24% 5.31 kB 5.32 kB
facebook-www/React-profiling.modern.js +0.26% 21.11 kB 21.16 kB +0.24% 5.39 kB 5.40 kB
facebook-www/React-profiling.classic.js +0.26% 21.11 kB 21.16 kB +0.24% 5.39 kB 5.40 kB

Generated by 🚫 dangerJS against f7d041a

Copy link
Collaborator

@unstubbable unstubbable left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, this will be very useful for frameworks and libraries!

expect(clientError.message).toBe('Timed out');
}
expect(clientError.digest).toBe('hi');
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fatal error case is missing.

@sebmarkbage sebmarkbage merged commit e1dc034 into facebook:main Jun 17, 2025
247 checks passed
github-actions bot pushed a commit that referenced this pull request Jun 17, 2025
This was really meant to be there from the beginning. A `cache()`:ed entry has a life time. On the server this ends when the render finishes. On the client this ends when the cache of that scope gets refreshed. When a cache is no longer needed, it should be possible to abort any outstanding network requests or other resources. That's what `cacheSignal()` gives you. It returns an `AbortSignal` which aborts when the cache lifetime is done based on the same execution scope as a `cache()`ed function - i.e. `AsyncLocalStorage` on the server or the render scope on the client. ```js import {cacheSignal} from 'react'; async function Component() { await fetch(url, { signal: cacheSignal() }); } ``` For `fetch` in particular, a patch should really just do this automatically for you. But it's useful for other resources like database connections. Another reason it's useful to have a `cacheSignal()` is to ignore any errors that might have triggered from the act of being aborted. This is just a general useful JavaScript pattern if you have access to a signal: ```js async function getData(id, signal) { try { await queryDatabase(id, { signal }); } catch (x) { if (!signal.aborted) { logError(x); // only log if it's a real error and not due to cancellation } return null; } } ``` This just gets you a convenient way to get to it without drilling through so a more idiomatic code in React might look something like. ```js import {cacheSignal} from "react"; async function getData(id) { try { await queryDatabase(id); } catch (x) { if (!cacheSignal()?.aborted) { logError(x); } return null; } } ``` If it's called outside of a React render, we normally treat any cached functions as uncached. They're not an error call. They can still load data. It's just not cached. This is not like an aborted signal because then you couldn't issue any requests. It's also not like an infinite abort signal because it's not actually cached forever. Therefore, `cacheSignal()` returns `null` when called outside of a React render scope. Notably the `signal` option passed to `renderToReadableStream` in both SSR (Fizz) and RSC (Flight Server) is not the same instance that comes out of `cacheSignal()`. If you abort the `signal` passed in, then the `cacheSignal()` is also aborted with the same reason. However, the `cacheSignal()` can also get aborted if the render completes successfully or fatally errors during render - allowing any outstanding work that wasn't used to clean up. In the future we might also expand on this to give different [`TaskSignal`](https://developer.mozilla.org/en-US/docs/Web/API/TaskSignal) to different scopes to pass different render or network priorities. On the client version of `"react"` this exposes a noop (both for Fiber/Fizz) due to `disableClientCache` flag but it's exposed so that you can write shared code. DiffTrain build for [e1dc034](e1dc034)
github-actions bot pushed a commit that referenced this pull request Jun 17, 2025
This was really meant to be there from the beginning. A `cache()`:ed entry has a life time. On the server this ends when the render finishes. On the client this ends when the cache of that scope gets refreshed. When a cache is no longer needed, it should be possible to abort any outstanding network requests or other resources. That's what `cacheSignal()` gives you. It returns an `AbortSignal` which aborts when the cache lifetime is done based on the same execution scope as a `cache()`ed function - i.e. `AsyncLocalStorage` on the server or the render scope on the client. ```js import {cacheSignal} from 'react'; async function Component() { await fetch(url, { signal: cacheSignal() }); } ``` For `fetch` in particular, a patch should really just do this automatically for you. But it's useful for other resources like database connections. Another reason it's useful to have a `cacheSignal()` is to ignore any errors that might have triggered from the act of being aborted. This is just a general useful JavaScript pattern if you have access to a signal: ```js async function getData(id, signal) { try { await queryDatabase(id, { signal }); } catch (x) { if (!signal.aborted) { logError(x); // only log if it's a real error and not due to cancellation } return null; } } ``` This just gets you a convenient way to get to it without drilling through so a more idiomatic code in React might look something like. ```js import {cacheSignal} from "react"; async function getData(id) { try { await queryDatabase(id); } catch (x) { if (!cacheSignal()?.aborted) { logError(x); } return null; } } ``` If it's called outside of a React render, we normally treat any cached functions as uncached. They're not an error call. They can still load data. It's just not cached. This is not like an aborted signal because then you couldn't issue any requests. It's also not like an infinite abort signal because it's not actually cached forever. Therefore, `cacheSignal()` returns `null` when called outside of a React render scope. Notably the `signal` option passed to `renderToReadableStream` in both SSR (Fizz) and RSC (Flight Server) is not the same instance that comes out of `cacheSignal()`. If you abort the `signal` passed in, then the `cacheSignal()` is also aborted with the same reason. However, the `cacheSignal()` can also get aborted if the render completes successfully or fatally errors during render - allowing any outstanding work that wasn't used to clean up. In the future we might also expand on this to give different [`TaskSignal`](https://developer.mozilla.org/en-US/docs/Web/API/TaskSignal) to different scopes to pass different render or network priorities. On the client version of `"react"` this exposes a noop (both for Fiber/Fizz) due to `disableClientCache` flag but it's exposed so that you can write shared code. DiffTrain build for [e1dc034](e1dc034)
ch4og pushed a commit to csmplay/csm-mapban that referenced this pull request Nov 18, 2025
This PR contains the following updates: | Package | Change | Age | Confidence | |---|---|---|---| | [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react) ([source](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react)) | [`19.1.10` -> `19.2.6`](https://renovatebot.com/diffs/npm/@types%2freact/19.1.10/19.2.6) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@types%2freact/19.2.6?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@types%2freact/19.1.10/19.2.6?slim=true)](https://docs.renovatebot.com/merge-confidence/) | | [@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react-dom) ([source](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom)) | [`19.1.7` -> `19.2.3`](https://renovatebot.com/diffs/npm/@types%2freact-dom/19.1.7/19.2.3) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@types%2freact-dom/19.2.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@types%2freact-dom/19.1.7/19.2.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | | [react](https://react.dev/) ([source](https://github.com/facebook/react/tree/HEAD/packages/react)) | [`19.1.1` -> `19.2.0`](https://renovatebot.com/diffs/npm/react/19.1.1/19.2.0) | [![age](https://developer.mend.io/api/mc/badges/age/npm/react/19.2.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/react/19.1.1/19.2.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | | [react-dom](https://react.dev/) ([source](https://github.com/facebook/react/tree/HEAD/packages/react-dom)) | [`19.1.1` -> `19.2.0`](https://renovatebot.com/diffs/npm/react-dom/19.1.1/19.2.0) | [![age](https://developer.mend.io/api/mc/badges/age/npm/react-dom/19.2.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/react-dom/19.1.1/19.2.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes <details> <summary>facebook/react (react)</summary> ### [`v19.2.0`](https://github.com/facebook/react/blob/HEAD/CHANGELOG.md#1920-October-1st-2025) [Compare Source](facebook/react@v19.1.1...v19.2.0) Below is a list of all new features, APIs, and bug fixes. Read the [React 19.2 release post](https://react.dev/blog/2025/10/01/react-19-2) for more information. ##### New React Features - [`<Activity>`](https://react.dev/reference/react/Activity): A new API to hide and restore the UI and internal state of its children. - [`useEffectEvent`](https://react.dev/reference/react/useEffectEvent) is a React Hook that lets you extract non-reactive logic into an [Effect Event](https://react.dev/learn/separating-events-from-effects#declaring-an-effect-event). - [`cacheSignal`](https://react.dev/reference/react/cacheSignal) (for RSCs) lets your know when the `cache()` lifetime is over. - [React Performance tracks](https://react.dev/reference/dev-tools/react-performance-tracks) appear on the Performance panel’s timeline in your browser developer tools ##### New React DOM Features - Added resume APIs for partial pre-rendering with Web Streams: - [`resume`](https://react.dev/reference/react-dom/server/resume): to resume a prerender to a stream. - [`resumeAndPrerender`](https://react.dev/reference/react-dom/static/resumeAndPrerender): to resume a prerender to HTML. - Added resume APIs for partial pre-rendering with Node Streams: - [`resumeToPipeableStream`](https://react.dev/reference/react-dom/server/resumeToPipeableStream): to resume a prerender to a stream. - [`resumeAndPrerenderToNodeStream`](https://react.dev/reference/react-dom/static/resumeAndPrerenderToNodeStream): to resume a prerender to HTML. - Updated [`prerender`](https://react.dev/reference/react-dom/static/prerender) APIs to return a `postponed` state that can be passed to the `resume` APIs. ##### Notable changes - React DOM now batches suspense boundary reveals, matching the behavior of client side rendering. This change is especially noticeable when animating the reveal of Suspense boundaries e.g. with the upcoming `<ViewTransition>` Component. React will batch as much reveals as possible before the first paint while trying to hit popular first-contentful paint metrics. - Add Node Web Streams (`prerender`, `renderToReadableStream`) to server-side-rendering APIs for Node.js - Use underscore instead of `:` IDs generated by useId ##### All Changes ##### React - `<Activity />` was developed over many years, starting before `ClassComponent.setState` ([@&#8203;acdlite](https://github.com/acdlite) [@&#8203;sebmarkbage](https://github.com/sebmarkbage) and many others) - Stringify context as "SomeContext" instead of "SomeContext.Provider" ([@&#8203;kassens](https://github.com/kassens) [#&#8203;33507](facebook/react#33507)) - Include stack of cause of React instrumentation errors with `%o` placeholder ([@&#8203;eps1lon](https://github.com/eps1lon) [#&#8203;34198](facebook/react#34198)) - Fix infinite `useDeferredValue` loop in popstate event ([@&#8203;acdlite](https://github.com/acdlite) [#&#8203;32821](facebook/react#32821)) - Fix a bug when an initial value was passed to `useDeferredValue` ([@&#8203;acdlite](https://github.com/acdlite) [#&#8203;34376](facebook/react#34376)) - Fix a crash when submitting forms with Client Actions ([@&#8203;sebmarkbage](https://github.com/sebmarkbage) [#&#8203;33055](facebook/react#33055)) - Hide/unhide the content of dehydrated suspense boundaries if they resuspend ([@&#8203;sebmarkbage](https://github.com/sebmarkbage) [#&#8203;32900](facebook/react#32900)) - Avoid stack overflow on wide trees during Hot Reload ([@&#8203;sophiebits](https://github.com/sophiebits) [#&#8203;34145](facebook/react#34145)) - Improve Owner and Component stacks in various places ([@&#8203;sebmarkbage](https://github.com/sebmarkbage), [@&#8203;eps1lon](https://github.com/eps1lon): [#&#8203;33629](facebook/react#33629), [#&#8203;33724](facebook/react#33724), [#&#8203;32735](facebook/react#32735), [#&#8203;33723](facebook/react#33723)) - Add `cacheSignal` ([@&#8203;sebmarkbage](https://github.com/sebmarkbage) [#&#8203;33557](facebook/react#33557)) ##### React DOM - Block on Suspensey Fonts during reveal of server-side-rendered content ([@&#8203;sebmarkbage](https://github.com/sebmarkbage) [#&#8203;33342](facebook/react#33342)) - Use underscore instead of `:` for IDs generated by `useId` ([@&#8203;sebmarkbage](https://github.com/sebmarkbage), [@&#8203;eps1lon](https://github.com/eps1lon): [#&#8203;32001](facebook/react#32001), [#&#8203;33342](https://github.com/facebook/react/pull/33342)[#&#8203;33099](https://github.com/facebook/react/pull/33099), [#&#8203;33422](facebook/react#33422)) - Stop warning when ARIA 1.3 attributes are used ([@&#8203;Abdul-Omira](https://github.com/Abdul-Omira) [#&#8203;34264](facebook/react#34264)) - Allow `nonce` to be used on hoistable styles ([@&#8203;Andarist](https://github.com/Andarist) [#&#8203;32461](facebook/react#32461)) - Warn for using a React owned node as a Container if it also has text content ([@&#8203;sebmarkbage](https://github.com/sebmarkbage) [#&#8203;32774](facebook/react#32774)) - s/HTML/text for for error messages if text hydration mismatches ([@&#8203;rickhanlonii](https://github.com/rickhanlonii) [#&#8203;32763](facebook/react#32763)) - Fix a bug with `React.use` inside `React.lazy`-ed Component ([@&#8203;hi-ogawa](https://github.com/hi-ogawa) [#&#8203;33941](facebook/react#33941)) - Enable the `progressiveChunkSize` option for server-side-rendering APIs ([@&#8203;sebmarkbage](https://github.com/sebmarkbage) [#&#8203;33027](facebook/react#33027)) - Fix a bug with deeply nested Suspense inside Suspense fallback when server-side-rendering ([@&#8203;gnoff](https://github.com/gnoff) [#&#8203;33467](facebook/react#33467)) - Avoid hanging when suspending after aborting while rendering ([@&#8203;gnoff](https://github.com/gnoff) [#&#8203;34192](facebook/react#34192)) - Add Node Web Streams to server-side-rendering APIs for Node.js ([@&#8203;sebmarkbage](https://github.com/sebmarkbage) [#&#8203;33475](facebook/react#33475)) ##### React Server Components - Preload `<img>` and `<link>` using hints before they're rendered ([@&#8203;sebmarkbage](https://github.com/sebmarkbage) [#&#8203;34604](facebook/react#34604)) - Log error if production elements are rendered during development ([@&#8203;eps1lon](https://github.com/eps1lon) [#&#8203;34189](facebook/react#34189)) - Fix a bug when returning a Temporary reference (e.g. a Client Reference) from Server Functions ([@&#8203;sebmarkbage](https://github.com/sebmarkbage) [#&#8203;34084](facebook/react#34084), [@&#8203;denk0403](https://github.com/denk0403) [#&#8203;33761](facebook/react#33761)) - Pass line/column to `filterStackFrame` ([@&#8203;eps1lon](https://github.com/eps1lon) [#&#8203;33707](facebook/react#33707)) - Support Async Modules in Turbopack Server References ([@&#8203;lubieowoce](https://github.com/lubieowoce) [#&#8203;34531](facebook/react#34531)) - Add support for .mjs file extension in Webpack ([@&#8203;jennyscript](https://github.com/jennyscript) [#&#8203;33028](facebook/react#33028)) - Fix a wrong missing key warning ([@&#8203;unstubbable](https://github.com/unstubbable) [#&#8203;34350](facebook/react#34350)) - Make console log resolve in predictable order ([@&#8203;sebmarkbage](https://github.com/sebmarkbage) [#&#8203;33665](facebook/react#33665)) ##### React Reconciler - [createContainer](https://github.com/facebook/react/blob/v19.2.0/packages/react-reconciler/src/ReactFiberReconciler.js#L255-L261) and [createHydrationContainer](https://github.com/facebook/react/blob/v19.2.0/packages/react-reconciler/src/ReactFiberReconciler.js#L305-L312) had their parameter order adjusted after `on*` handlers to account for upcoming experimental APIs </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://github.com/renovatebot/renovate/discussions) if that's undesired. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS4xNDguNCIsInVwZGF0ZWRJblZlciI6IjQyLjEwLjUiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbXX0=--> Reviewed-on: https://git.in.csmpro.ru/csmpro/csm-mapban/pulls/36 Co-authored-by: Renovate Bot <renovate@csmpro.ru> Co-committed-by: Renovate Bot <renovate@csmpro.ru>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed React Core Team Opened by a member of the React Core Team

4 participants