Skip to content

Update stack diffing algorithm in describeNativeComponentFrame #27132

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Nov 8, 2023

Conversation

KarimP
Copy link
Contributor

@KarimP KarimP commented Jul 19, 2023

Summary

There's a bug with the existing stack comparison algorithm in describeNativeComponentFrame — specifically how it attempts to find a common root frame between the control and sample stacks. This PR attempts to fix that bug by injecting a frame that can have a guaranteed string in it for us to search for in both stacks to find a common root.

Brief Background/How it works now

Right now describeNativeComponentFrame does the following to leverage native browser/VM stack frames to get details (e.g. script path, row and col #s) for a single component:

  1. Throwing and catching a control error in the function
  2. Calling the component which should eventually throw an error (most of the time), that we'll catch as our sample error.
  3. Diffing the stacks in the control and sample errors to find the line which should represent our component call.

What's broken

To account for potential stack trace truncation, the stack diffing algorithm first attempts to find a common "root" frame by inspecting the earliest frame of the sample stack and searching for an identical frame in the control stack starting from the bottom. However, there are a couple of scenarios which I've hit that cause the above approach to not work correctly.

First, it's possible that for render passes of extremely large component trees to have a lot of repeating internal react function calls, which can result in an incorrect common or "root" frame found. Here's a small example from a stack trace using React Fizz for SSR.
Our control frame can look like this:

Error:
    at Fake (...)
    at construct (native)
    at describeNativeComponentFrame (...)
    at describeClassComponentFrame (...)
    at getStackByComponentStackNode (...)
    at getCurrentStackInDEV (...)
    at renderNodeDestructive (...)
    at renderElement (...)
    at renderNodeDestructiveImpl (...) // <-- Actual common root frame with the sample stack
    at renderNodeDestructive (...)
    at renderElement (...)
    at renderNodeDestructiveImpl (...) // <-- Incorrectly chosen common root frame
    at renderNodeDestructive (...)

And our sample stack can look like this:

Error:
    at set (...)
    at PureComponent (...)
    at call (native)
    at apply (native)
    at ErrorBoundary (...)
    at construct (native)
    at describeNativeComponentFrame (...)
    at describeClassComponentFrame (...)
    at getStackByComponentStackNode (...)
    at getCurrentStackInDEV (...)
    at renderNodeDestructive (...)
    at renderElement (...)
    at renderNodeDestructiveImpl (...) // <-- Root frame that's common in the control stack

Here you can see that the earliest trace in the sample stack, the renderNodeDestructiveImpl call, can exactly match with multiple renderNodeDestructiveImpl calls in the control stack (including file path and line + col #s). Currently the algorithm will chose the earliest/last frame with the renderNodeDestructiveImpl call (which is the second last frame in our control stack), which is incorrect. The actual matching frame in the control stack is the latest or first frame (when traversing from the top) with the renderNodeDestructiveImpl call. This leads to the rest of the stack diffing associating an incorrect frame (at getStackByComponentStackNode (...)) for the component.

Another issue with this approach is that it assumes all VMs will truncate stack traces at the bottom, which isn't the case for the Hermes VM which truncates stack traces in the middle, placing a

    at renderNodeDestructiveImpl (...)
    ... skipping {n} frames
    at renderNodeDestructive (...)

line in the middle of the stack trace for all stacks that contain more than 100 traces. This causes stack traces for React Native apps using the Hermes VM to potentially break for large component trees. Although for this specific case with Hermes, it's possible to account for this by either manually grepping and removing the ... skipping line and everything below it (see draft PR: #26999), or by implementing the non-standard prepareStackTrace API which Hermes also supports to manually generate a stack trace that truncates from the bottom (example implementation).

The Fix

I found different ways to go about fixing this. The first was to search for a common stack frame starting from the top/latest frame. It's a relatively small change (see implementation), although it is less performant by being n^2 (albeit with n realistically being <= 5 here). It's also a bit more buggy for class components given that different VMs insert a different amount of additional lines for new/construct calls...

Another fix would be to actually implement a longest common substring algorithm, which can also be roughly n^2 time (assuming the longest common substring between control and sample will be most of the sample frame).

The fix I ended up going with was have the lines that throw the control error and the lines that call/instantiate the component be inside a distinct method under an object property ("DescribeNativeComponentFrameRoot"). All major VMs (Safari's JavaScriptCore, Firefox's SpiderMonkey, V8, Hermes, and Bun) should display the object property name their stack trace. I've also set the name and displayName properties for method as well to account for minification, any advanced optimizations (e.g. key crushing), and VM inconsistencies (both Bun and Safari seem to exclusively use the value under displayName and not name in traces for methods defined under an object's own property...).

We can then find this "common" frame by simply finding the line that has our special method name ("DescribeNativeComponentFrameRoot"), and the rest of the code to determine the actual component line works as expected. If by any chance we don't find a frame with our special method name in either control or sample stack traces, we then revert back to the existing approach mentioned above by searching for the last line of the sample frame in the control frame.

How did you test this change?

  1. There are bunch of existing tests that ensure a properly formatted component trace is logged for certain scenarios, so I ensured the existing full test suite passed
  2. I threw an error in a component that's deep in the component hierarchy of a large React app (facebook) to ensure there's stack trace truncation, and ensured the correct component stack trace was logged for Chrome, Safari, and Firefox, and with and without minification.
  3. Ran a large React app (facebook) on the Hermes VM, threw an error in a component that's deep in the component hierarchy, and ensured that component frames are generated despite stack traces being truncated in the middle.

- Attempt have a predefined "root" or common frame between sample and
  control frames
@react-sizebot
Copy link

react-sizebot commented Jul 19, 2023

Comparing: 94d5b5b...38abf48

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.min.js +0.35% 167.45 kB 168.03 kB +0.33% 52.15 kB 52.32 kB
oss-experimental/react-dom/cjs/react-dom.production.min.js +0.33% 176.11 kB 176.69 kB +0.31% 54.84 kB 55.01 kB
facebook-www/ReactDOM-prod.classic.js +0.35% 563.33 kB 565.31 kB +0.30% 99.28 kB 99.58 kB
facebook-www/ReactDOM-prod.modern.js +0.36% 547.06 kB 549.04 kB +0.31% 96.35 kB 96.65 kB
oss-experimental/react/cjs/react-jsx-dev-runtime.development.js +6.96% 43.32 kB 46.34 kB +6.53% 12.65 kB 13.47 kB
oss-stable-semver/react/cjs/react-jsx-dev-runtime.development.js +6.96% 43.35 kB 46.36 kB +6.53% 12.65 kB 13.48 kB
oss-stable/react/cjs/react-jsx-dev-runtime.development.js +6.96% 43.35 kB 46.36 kB +6.53% 12.65 kB 13.48 kB
facebook-www/JSXDEVRuntime-dev.modern.js +6.87% 45.15 kB 48.25 kB +6.71% 12.82 kB 13.68 kB
facebook-www/JSXDEVRuntime-dev.classic.js +6.87% 45.15 kB 48.25 kB +6.71% 12.82 kB 13.68 kB
oss-experimental/react/cjs/react-jsx-runtime.development.js +6.87% 43.92 kB 46.93 kB +6.45% 12.82 kB 13.65 kB
oss-stable-semver/react/cjs/react-jsx-runtime.development.js +6.86% 43.94 kB 46.96 kB +6.46% 12.83 kB 13.65 kB
oss-stable/react/cjs/react-jsx-runtime.development.js +6.86% 43.94 kB 46.96 kB +6.46% 12.83 kB 13.65 kB
oss-stable-semver/react/cjs/react.shared-subset.development.js +3.56% 84.72 kB 87.74 kB +3.72% 23.50 kB 24.37 kB
oss-stable/react/cjs/react.shared-subset.development.js +3.56% 84.75 kB 87.76 kB +3.72% 23.53 kB 24.41 kB
oss-experimental/react/cjs/react.shared-subset.development.js +3.49% 86.40 kB 89.42 kB +3.73% 24.00 kB 24.90 kB
oss-stable-semver/react/cjs/react.development.js +3.02% 99.79 kB 102.80 kB +3.22% 26.94 kB 27.81 kB
oss-stable/react/cjs/react.development.js +3.02% 99.81 kB 102.83 kB +3.22% 26.97 kB 27.84 kB
oss-experimental/react/cjs/react.development.js +2.95% 102.28 kB 105.30 kB +3.04% 27.60 kB 28.44 kB
oss-stable-semver/react/umd/react.development.js +2.55% 122.92 kB 126.05 kB +2.66% 31.78 kB 32.63 kB
oss-stable/react/umd/react.development.js +2.55% 122.95 kB 126.08 kB +2.65% 31.81 kB 32.66 kB
oss-experimental/react/umd/react.development.js +2.49% 125.52 kB 128.65 kB +2.69% 32.43 kB 33.30 kB
facebook-www/React-dev.modern.js +2.46% 125.87 kB 128.97 kB +2.79% 33.36 kB 34.29 kB
facebook-www/React-dev.classic.js +2.44% 126.97 kB 130.07 kB +2.86% 33.61 kB 34.57 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/cjs/react-jsx-dev-runtime.development.js +6.96% 43.32 kB 46.34 kB +6.53% 12.65 kB 13.47 kB
oss-stable-semver/react/cjs/react-jsx-dev-runtime.development.js +6.96% 43.35 kB 46.36 kB +6.53% 12.65 kB 13.48 kB
oss-stable/react/cjs/react-jsx-dev-runtime.development.js +6.96% 43.35 kB 46.36 kB +6.53% 12.65 kB 13.48 kB
facebook-www/JSXDEVRuntime-dev.modern.js +6.87% 45.15 kB 48.25 kB +6.71% 12.82 kB 13.68 kB
facebook-www/JSXDEVRuntime-dev.classic.js +6.87% 45.15 kB 48.25 kB +6.71% 12.82 kB 13.68 kB
oss-experimental/react/cjs/react-jsx-runtime.development.js +6.87% 43.92 kB 46.93 kB +6.45% 12.82 kB 13.65 kB
oss-stable-semver/react/cjs/react-jsx-runtime.development.js +6.86% 43.94 kB 46.96 kB +6.46% 12.83 kB 13.65 kB
oss-stable/react/cjs/react-jsx-runtime.development.js +6.86% 43.94 kB 46.96 kB +6.46% 12.83 kB 13.65 kB
oss-stable-semver/react/cjs/react.shared-subset.development.js +3.56% 84.72 kB 87.74 kB +3.72% 23.50 kB 24.37 kB
oss-stable/react/cjs/react.shared-subset.development.js +3.56% 84.75 kB 87.76 kB +3.72% 23.53 kB 24.41 kB
oss-experimental/react/cjs/react.shared-subset.development.js +3.49% 86.40 kB 89.42 kB +3.73% 24.00 kB 24.90 kB
oss-stable-semver/react/cjs/react.development.js +3.02% 99.79 kB 102.80 kB +3.22% 26.94 kB 27.81 kB
oss-stable/react/cjs/react.development.js +3.02% 99.81 kB 102.83 kB +3.22% 26.97 kB 27.84 kB
oss-experimental/react/cjs/react.development.js +2.95% 102.28 kB 105.30 kB +3.04% 27.60 kB 28.44 kB
oss-stable-semver/react/umd/react.development.js +2.55% 122.92 kB 126.05 kB +2.66% 31.78 kB 32.63 kB
oss-stable/react/umd/react.development.js +2.55% 122.95 kB 126.08 kB +2.65% 31.81 kB 32.66 kB
oss-experimental/react/umd/react.development.js +2.49% 125.52 kB 128.65 kB +2.69% 32.43 kB 33.30 kB
facebook-www/React-dev.modern.js +2.46% 125.87 kB 128.97 kB +2.79% 33.36 kB 34.29 kB
facebook-www/React-dev.classic.js +2.44% 126.97 kB 130.07 kB +2.86% 33.61 kB 34.57 kB
oss-stable-semver/react-server/cjs/react-server.development.js +1.69% 178.91 kB 181.93 kB +2.02% 41.49 kB 42.32 kB
oss-stable/react-server/cjs/react-server.development.js +1.69% 178.91 kB 181.93 kB +2.02% 41.49 kB 42.32 kB
oss-experimental/react-server/cjs/react-server.development.js +1.53% 196.55 kB 199.57 kB +1.82% 45.60 kB 46.43 kB
oss-stable-semver/react-dom/cjs/react-dom-server.bun.development.js +0.82% 366.51 kB 369.52 kB +1.03% 80.69 kB 81.53 kB
oss-stable/react-dom/cjs/react-dom-server.bun.development.js +0.82% 366.53 kB 369.55 kB +1.03% 80.72 kB 81.55 kB
oss-stable-semver/react-dom/cjs/react-dom-server.browser.development.js +0.82% 369.27 kB 372.28 kB +1.03% 81.59 kB 82.43 kB
oss-stable/react-dom/cjs/react-dom-server.browser.development.js +0.82% 369.29 kB 372.31 kB +1.03% 81.61 kB 82.46 kB
oss-stable-semver/react-dom/cjs/react-dom-server-legacy.browser.development.js +0.82% 369.34 kB 372.36 kB +1.04% 81.15 kB 82.00 kB
oss-stable/react-dom/cjs/react-dom-server-legacy.browser.development.js +0.82% 369.37 kB 372.38 kB +1.04% 81.18 kB 82.03 kB
oss-stable-semver/react-dom/cjs/react-dom-server.edge.development.js +0.82% 369.68 kB 372.69 kB +1.04% 81.71 kB 82.55 kB
oss-stable/react-dom/cjs/react-dom-server.edge.development.js +0.82% 369.70 kB 372.72 kB +1.03% 81.73 kB 82.58 kB
oss-stable-semver/react-dom/cjs/react-dom-server.node.development.js +0.81% 370.75 kB 373.77 kB +1.03% 81.63 kB 82.47 kB
oss-stable/react-dom/cjs/react-dom-server.node.development.js +0.81% 370.78 kB 373.79 kB +1.03% 81.65 kB 82.50 kB
oss-stable-semver/react-dom/cjs/react-dom-server-legacy.node.development.js +0.81% 371.20 kB 374.21 kB +1.04% 81.61 kB 82.45 kB
oss-stable/react-dom/cjs/react-dom-server-legacy.node.development.js +0.81% 371.22 kB 374.24 kB +1.04% 81.64 kB 82.48 kB
facebook-www/ReactDOMServerStreaming-dev.modern.js +0.81% 382.80 kB 385.90 kB +1.04% 84.23 kB 85.11 kB
oss-stable-semver/react-dom/umd/react-dom-server.browser.development.js +0.81% 387.07 kB 390.20 kB +1.04% 82.52 kB 83.38 kB
oss-stable/react-dom/umd/react-dom-server.browser.development.js +0.81% 387.10 kB 390.23 kB +1.04% 82.55 kB 83.41 kB
oss-stable-semver/react-dom/umd/react-dom-server-legacy.browser.development.js +0.81% 387.16 kB 390.29 kB +1.05% 82.07 kB 82.93 kB
oss-stable/react-dom/umd/react-dom-server-legacy.browser.development.js +0.81% 387.19 kB 390.32 kB +1.05% 82.10 kB 82.96 kB
facebook-www/ReactDOMServer-dev.modern.js +0.80% 388.10 kB 391.20 kB +1.01% 85.50 kB 86.36 kB
facebook-www/ReactDOMServer-dev.classic.js +0.78% 395.53 kB 398.63 kB +0.99% 87.14 kB 88.01 kB
oss-experimental/react-dom/cjs/react-dom-server.bun.development.js +0.77% 389.80 kB 392.81 kB +0.99% 85.64 kB 86.48 kB
oss-experimental/react-dom/cjs/react-dom-server-legacy.browser.development.js +0.76% 396.30 kB 399.31 kB +0.97% 87.63 kB 88.48 kB
oss-experimental/react-dom/cjs/react-dom-server-legacy.node.development.js +0.76% 398.15 kB 401.17 kB +0.97% 88.09 kB 88.94 kB
oss-experimental/react-dom/umd/react-dom-server-legacy.browser.development.js +0.75% 415.21 kB 418.34 kB +0.99% 88.95 kB 89.83 kB
oss-experimental/react-dom/cjs/react-dom-server.node.development.js +0.75% 399.93 kB 402.95 kB +0.97% 87.22 kB 88.07 kB
oss-experimental/react-dom/cjs/react-dom-server.browser.development.js +0.75% 402.35 kB 405.36 kB +0.96% 88.36 kB 89.22 kB
oss-experimental/react-dom/cjs/react-dom-server.edge.development.js +0.75% 402.76 kB 405.77 kB +0.98% 88.48 kB 89.35 kB
oss-experimental/react-dom/umd/react-dom-server.browser.development.js +0.74% 421.56 kB 424.69 kB +0.94% 89.72 kB 90.56 kB
oss-stable-semver/react-art/cjs/react-art.production.min.js +0.62% 94.35 kB 94.93 kB +0.59% 29.03 kB 29.20 kB
oss-stable/react-art/cjs/react-art.production.min.js +0.62% 94.40 kB 94.98 kB +0.59% 29.06 kB 29.23 kB
facebook-www/ReactART-prod.modern.js +0.59% 335.39 kB 337.38 kB +0.53% 57.04 kB 57.34 kB
oss-experimental/react-art/cjs/react-art.production.min.js +0.58% 99.84 kB 100.43 kB +0.61% 30.59 kB 30.78 kB
facebook-www/ReactART-prod.classic.js +0.57% 346.39 kB 348.37 kB +0.49% 58.94 kB 59.23 kB
oss-stable-semver/react-test-renderer/cjs/react-test-renderer.production.min.js +0.56% 103.40 kB 103.98 kB +0.61% 31.76 kB 31.95 kB
oss-stable/react-test-renderer/cjs/react-test-renderer.production.min.js +0.56% 103.46 kB 104.04 kB +0.62% 31.78 kB 31.98 kB
oss-experimental/react-test-renderer/cjs/react-test-renderer.production.min.js +0.56% 103.58 kB 104.16 kB +0.60% 31.83 kB 32.02 kB
oss-stable-semver/react-test-renderer/umd/react-test-renderer.production.min.js +0.56% 103.79 kB 104.37 kB +0.54% 32.19 kB 32.37 kB
oss-stable/react-test-renderer/umd/react-test-renderer.production.min.js +0.56% 103.84 kB 104.42 kB +0.54% 32.22 kB 32.39 kB
oss-experimental/react-test-renderer/umd/react-test-renderer.production.min.js +0.56% 103.97 kB 104.55 kB +0.56% 32.26 kB 32.45 kB
oss-stable-semver/react-reconciler/cjs/react-reconciler.production.min.js +0.53% 110.52 kB 111.10 kB +0.57% 33.68 kB 33.87 kB
oss-stable/react-reconciler/cjs/react-reconciler.production.min.js +0.53% 110.54 kB 111.13 kB +0.57% 33.70 kB 33.90 kB
oss-experimental/react-reconciler/cjs/react-reconciler.production.min.js +0.50% 116.57 kB 117.15 kB +0.54% 35.53 kB 35.72 kB
oss-stable-semver/react-reconciler/cjs/react-reconciler.profiling.min.js +0.49% 119.54 kB 120.12 kB +0.54% 35.92 kB 36.11 kB
oss-stable/react-reconciler/cjs/react-reconciler.profiling.min.js +0.49% 119.56 kB 120.14 kB +0.54% 35.94 kB 36.14 kB
oss-experimental/react-reconciler/cjs/react-reconciler.profiling.min.js +0.46% 125.59 kB 126.17 kB +0.54% 37.78 kB 37.98 kB
oss-stable-semver/react-art/umd/react-art.production.min.js +0.44% 131.64 kB 132.22 kB +0.43% 41.20 kB 41.38 kB
oss-stable/react-art/umd/react-art.production.min.js +0.44% 131.69 kB 132.27 kB +0.42% 41.22 kB 41.40 kB
oss-experimental/react-art/umd/react-art.production.min.js +0.42% 137.11 kB 137.69 kB +0.46% 42.72 kB 42.91 kB
facebook-www/ReactTestRenderer-dev.modern.js +0.38% 805.72 kB 808.82 kB +0.50% 175.03 kB 175.91 kB
facebook-www/ReactTestRenderer-dev.classic.js +0.38% 805.72 kB 808.82 kB +0.50% 175.03 kB 175.91 kB
oss-stable-semver/react-test-renderer/cjs/react-test-renderer.development.js +0.38% 787.36 kB 790.38 kB +0.49% 172.78 kB 173.64 kB
oss-stable/react-test-renderer/cjs/react-test-renderer.development.js +0.38% 787.39 kB 790.40 kB +0.50% 172.82 kB 173.68 kB
oss-experimental/react-test-renderer/cjs/react-test-renderer.development.js +0.38% 787.76 kB 790.77 kB +0.50% 172.90 kB 173.76 kB
oss-stable-semver/react-test-renderer/umd/react-test-renderer.development.js +0.38% 824.63 kB 827.76 kB +0.48% 174.59 kB 175.44 kB
oss-stable/react-test-renderer/umd/react-test-renderer.development.js +0.38% 824.65 kB 827.79 kB +0.48% 174.62 kB 175.47 kB
oss-experimental/react-test-renderer/umd/react-test-renderer.development.js +0.38% 825.04 kB 828.18 kB +0.48% 174.71 kB 175.56 kB
oss-stable-semver/react-art/cjs/react-art.development.js +0.37% 805.36 kB 808.38 kB +0.48% 176.32 kB 177.16 kB
oss-stable/react-art/cjs/react-art.development.js +0.37% 805.39 kB 808.40 kB +0.47% 176.35 kB 177.19 kB
facebook-www/ReactDOM-prod.modern.js +0.36% 547.06 kB 549.04 kB +0.31% 96.35 kB 96.65 kB
oss-experimental/react-art/cjs/react-art.development.js +0.36% 838.22 kB 841.24 kB +0.46% 182.53 kB 183.37 kB
facebook-www/ReactDOM-prod.classic.js +0.35% 563.33 kB 565.31 kB +0.30% 99.28 kB 99.58 kB
facebook-www/ReactDOMTesting-prod.modern.js +0.35% 563.60 kB 565.58 kB +0.30% 100.51 kB 100.81 kB
oss-stable-semver/react-dom/umd/react-dom.production.min.js +0.35% 167.23 kB 167.81 kB +0.31% 52.44 kB 52.61 kB
oss-stable/react-dom/umd/react-dom.production.min.js +0.35% 167.31 kB 167.89 kB +0.32% 52.47 kB 52.64 kB
oss-stable-semver/react-dom/cjs/react-dom.production.min.js +0.35% 167.37 kB 167.95 kB +0.34% 52.12 kB 52.29 kB
oss-stable/react-dom/cjs/react-dom.production.min.js +0.35% 167.45 kB 168.03 kB +0.33% 52.15 kB 52.32 kB
facebook-www/ReactDOM-profiling.modern.js +0.34% 577.58 kB 579.56 kB +0.30% 100.93 kB 101.24 kB
facebook-www/ReactDOMTesting-prod.classic.js +0.34% 578.15 kB 580.13 kB +0.30% 103.01 kB 103.32 kB
facebook-www/ReactART-dev.modern.js +0.34% 906.26 kB 909.36 kB +0.45% 193.54 kB 194.42 kB
oss-stable-semver/react-art/umd/react-art.development.js +0.34% 920.20 kB 923.33 kB +0.44% 195.37 kB 196.22 kB
oss-stable/react-art/umd/react-art.development.js +0.34% 920.22 kB 923.35 kB +0.44% 195.39 kB 196.24 kB
facebook-www/ReactART-dev.classic.js +0.34% 917.46 kB 920.56 kB +0.44% 195.85 kB 196.72 kB
oss-stable-semver/react-reconciler/cjs/react-reconciler.development.js +0.33% 901.33 kB 904.35 kB +0.44% 193.71 kB 194.56 kB
oss-stable/react-reconciler/cjs/react-reconciler.development.js +0.33% 901.36 kB 904.37 kB +0.44% 193.74 kB 194.59 kB
facebook-www/ReactDOM-profiling.classic.js +0.33% 593.93 kB 595.91 kB +0.29% 103.81 kB 104.11 kB
oss-experimental/react-dom/umd/react-dom.production.min.js +0.33% 175.88 kB 176.46 kB +0.30% 55.11 kB 55.28 kB
oss-experimental/react-dom/cjs/react-dom.production.min.js +0.33% 176.11 kB 176.69 kB +0.31% 54.84 kB 55.01 kB
oss-stable-semver/react-dom/umd/react-dom.profiling.min.js +0.33% 176.22 kB 176.80 kB +0.33% 54.82 kB 55.00 kB
oss-stable/react-dom/umd/react-dom.profiling.min.js +0.33% 176.30 kB 176.88 kB +0.32% 54.85 kB 55.03 kB
oss-stable-semver/react-dom/cjs/react-dom.profiling.min.js +0.33% 177.01 kB 177.59 kB +0.32% 54.57 kB 54.75 kB
oss-stable/react-dom/cjs/react-dom.profiling.min.js +0.33% 177.09 kB 177.67 kB +0.32% 54.59 kB 54.77 kB
oss-experimental/react-art/umd/react-art.development.js +0.33% 954.64 kB 957.77 kB +0.39% 201.61 kB 202.40 kB
oss-experimental/react-reconciler/cjs/react-reconciler.development.js +0.32% 937.52 kB 940.53 kB +0.44% 200.87 kB 201.75 kB
oss-experimental/react-dom/cjs/react-dom-unstable_testing.production.min.js +0.32% 182.32 kB 182.90 kB +0.30% 57.21 kB 57.38 kB
oss-experimental/react-dom/umd/react-dom.profiling.min.js +0.31% 184.88 kB 185.46 kB +0.29% 57.48 kB 57.64 kB
oss-experimental/react-dom/cjs/react-dom.profiling.min.js +0.31% 185.76 kB 186.34 kB +0.30% 57.27 kB 57.44 kB
oss-stable-semver/react-dom/cjs/react-dom.development.js +0.24% 1,275.49 kB 1,278.50 kB +0.29% 281.43 kB 282.24 kB
oss-stable/react-dom/cjs/react-dom.development.js +0.24% 1,275.52 kB 1,278.53 kB +0.29% 281.46 kB 282.27 kB
oss-stable-semver/react-dom/umd/react-dom.development.js +0.23% 1,337.07 kB 1,340.20 kB +0.29% 284.35 kB 285.19 kB
oss-stable/react-dom/umd/react-dom.development.js +0.23% 1,337.09 kB 1,340.22 kB +0.30% 284.38 kB 285.22 kB
oss-experimental/react-dom/cjs/react-dom.development.js +0.23% 1,330.58 kB 1,333.60 kB +0.29% 293.32 kB 294.17 kB
oss-experimental/react-dom/umd/react-dom.development.js +0.22% 1,394.71 kB 1,397.84 kB +0.30% 296.34 kB 297.22 kB
oss-experimental/react-dom/cjs/react-dom-unstable_testing.development.js +0.22% 1,348.64 kB 1,351.65 kB +0.28% 297.70 kB 298.55 kB
facebook-www/ReactDOM-dev.modern.js +0.22% 1,401.15 kB 1,404.25 kB +0.29% 303.44 kB 304.31 kB
facebook-www/ReactDOMTesting-dev.modern.js +0.22% 1,419.49 kB 1,422.59 kB +0.28% 307.85 kB 308.71 kB
facebook-www/ReactDOM-dev.classic.js +0.22% 1,429.05 kB 1,432.15 kB +0.28% 309.00 kB 309.87 kB
facebook-www/ReactDOMTesting-dev.classic.js +0.21% 1,447.40 kB 1,450.50 kB +0.27% 313.45 kB 314.30 kB

Generated by 🚫 dangerJS against 38abf48

// Before ES6, the `name` property was not configurable.
if (
// $FlowFixMe[method-unbinding]
Object.getOwnPropertyDescriptor(this.DetermineComponentFrameRoot)
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm should this be Object.getOwnPropertyDescriptor(this.DetermineComponentFrameRoot, 'name')?

Also JS q -- if the name property is not configurable, does that mean it should already hold the value DetermineComponentFrameRoot?

Copy link
Contributor Author

@KarimP KarimP Jul 19, 2023

Choose a reason for hiding this comment

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

Oh yup, I should specify 'name' there!

the name property is not configurable, does that mean it should already hold the value DetermineComponentFrameRoot

I think it depends on the JS VM? But yes for most the name property should automatically be set to the function name defined in code. However setting both name and displayName dynamically in code can account for any post-processing that might get done to the code. For example, it's possible for:

RunInRootFrame.DetermineComponentFrameRoot =
  function DetermineComponentFrameRoot() {
    ...
  };

to get minified to:

a.DetermineComponentFrameRoot = function b() {
  ...
};

In this case, I think most VMs would set the name property here to "b". Pre-ES6 it wouldn't be possible to change that. ES6 onwards the name property is not writable (so we can't directly set it via property access), but is configurable, so we can change it via Object.defineProperty. Also some VMs might specify both the function name and method name in stack traces, so e.g. V8 would have a stack trace line like:

    at a.b [as DetermineComponentFrameRoot] 

But it's not guaranteed for all VMs.

@mofeiZ
Copy link
Contributor

mofeiZ commented Jul 19, 2023

From circleci build-lint, it looks like React's umd bundles use ES5 (eslintrc).

@acdlite this might be a noob q, but what is stopping us from using ES6 features?

@KarimP
Copy link
Contributor Author

KarimP commented Jul 20, 2023

I removed the use of classes and switched over to having the function that throws the control and sample errors be under an object property. I initially chose a class method because the Closure compiler would elide my initial attempts to separate the code that throws control and sample errors to a different function, but now with my current changes that doesn't appear to be case... (I assume it might have to do with me setting the name and displayName properties on the function).

@Error75757575
Copy link

🌹

@mofeiZ
Copy link
Contributor

mofeiZ commented Aug 2, 2023

This looks good to me! I'd love for someone else to take a look before stamping -- @acdlite @gnoff are you familiar with this code (or know someone who is?)

const sampleLines = sampleStack.split('\n');
const controlLines = controlStack.split('\n');
let s = sampleLines.findIndex(line =>
line.includes('DetermineComponentFrameRoot'),
Copy link
Collaborator

Choose a reason for hiding this comment

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

I’d find some alternative methods to use here because newer methods tend to be slower. We don’t use the names elsewhere so compress worse. We also convert this away from arrow function so it’ll be longer than it looks.

There’s also the risk of older environments not supporting it.

Maybe just a plain loop.

Copy link
Collaborator

@sebmarkbage sebmarkbage left a comment

Choose a reason for hiding this comment

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

I think the approach generally makes sense.

@mofeiZ mofeiZ merged commit 88b00de into facebook:main Nov 8, 2023
github-actions bot pushed a commit that referenced this pull request Nov 8, 2023
## Summary

There's a bug with the existing stack comparison algorithm in
`describeNativeComponentFrame` — specifically how it attempts to find a
common root frame between the control and sample stacks. This PR
attempts to fix that bug by injecting a frame that can have a guaranteed
string in it for us to search for in both stacks to find a common root.

## Brief Background/How it works now

Right now `describeNativeComponentFrame` does the following to leverage
native browser/VM stack frames to get details (e.g. script path, row and
col #s) for a single component:
1. Throwing and catching a control error in the function
2. Calling the component which should eventually throw an error (most of
the time), that we'll catch as our sample error.
3. Diffing the stacks in the control and sample errors to find the line
which should represent our component call.

## What's broken

To account for potential stack trace truncation, the stack diffing
algorithm first attempts to find a common "root" frame by inspecting the
earliest frame of the sample stack and searching for an identical frame
in the control stack starting from the bottom. However, there are a
couple of scenarios which I've hit that cause the above approach to not
work correctly.

First, it's possible that for render passes of extremely large component
trees to have a lot of repeating internal react function calls, which
can result in an incorrect common or "root" frame found. Here's a small
example from a stack trace using React Fizz for SSR.
Our control frame can look like this:
```
Error:
    at Fake (...)
    at construct (native)
    at describeNativeComponentFrame (...)
    at describeClassComponentFrame (...)
    at getStackByComponentStackNode (...)
    at getCurrentStackInDEV (...)
    at renderNodeDestructive (...)
    at renderElement (...)
    at renderNodeDestructiveImpl (...) // <-- Actual common root frame with the sample stack
    at renderNodeDestructive (...)
    at renderElement (...)
    at renderNodeDestructiveImpl (...) // <-- Incorrectly chosen common root frame
    at renderNodeDestructive (...)
```

And our sample stack can look like this:
```
Error:
    at set (...)
    at PureComponent (...)
    at call (native)
    at apply (native)
    at ErrorBoundary (...)
    at construct (native)
    at describeNativeComponentFrame (...)
    at describeClassComponentFrame (...)
    at getStackByComponentStackNode (...)
    at getCurrentStackInDEV (...)
    at renderNodeDestructive (...)
    at renderElement (...)
    at renderNodeDestructiveImpl (...) // <-- Root frame that's common in the control stack
```

Here you can see that the earliest trace in the sample stack, the
`renderNodeDestructiveImpl` call, can exactly match with multiple
`renderNodeDestructiveImpl` calls in the control stack (including file
path and line + col #s). Currently the algorithm will chose the
earliest/last frame with the `renderNodeDestructiveImpl` call (which is
the second last frame in our control stack), which is incorrect. The
actual matching frame in the control stack is the latest or first frame
(when traversing from the top) with the `renderNodeDestructiveImpl`
call. This leads to the rest of the stack diffing associating an
incorrect frame (`at getStackByComponentStackNode (...)`) for the
component.

Another issue with this approach is that it assumes all VMs will
truncate stack traces at the *bottom*, [which isn't the case for the
Hermes
VM](https://github.com/facebook/hermes/blob/df07cf713a84a4434c83c08cede38ba438dc6aca/lib/VM/JSError.cpp#L688-L699)
which **truncates stack traces in the middle**, placing a

```
    at renderNodeDestructiveImpl (...)
    ... skipping {n} frames
    at renderNodeDestructive (...)
```

line in the middle of the stack trace for all stacks that contain more
than 100 traces. This causes stack traces for React Native apps using
the Hermes VM to potentially break for large component trees. Although
for this specific case with Hermes, it's possible to account for this by
either manually grepping and removing the `... skipping` line and
everything below it (see draft PR: #26999), or by implementing the
non-standard `prepareStackTrace` API which Hermes also supports to
manually generate a stack trace that truncates from the bottom ([example
implementation](main...KarimP:react:component-stack-hermes-fix)).

## The Fix

I found different ways to go about fixing this. The first was to search
for a common stack frame starting from the top/latest frame. It's a
relatively small change ([see
implementation](main...KarimP:react:component-stack-fix-2)),
although it is less performant by being n^2 (albeit with `n`
realistically being <= 5 here). It's also a bit more buggy for class
components given that different VMs insert a different amount of
additional lines for new/construct calls...

Another fix would be to actually implement a [longest common
substring](https://en.wikipedia.org/wiki/Longest_common_substring)
algorithm, which can also be roughly n^2 time (assuming the longest
common substring between control and sample will be most of the sample
frame).

The fix I ended up going with was have the lines that throw the control
error and the lines that call/instantiate the component be inside a
distinct method under an object property
(`"DescribeNativeComponentFrameRoot"`). All major VMs (Safari's
JavaScriptCore, Firefox's SpiderMonkey, V8, Hermes, and Bun) should
display the object property name their stack trace. I've also set the
`name` and `displayName` properties for method as well to account for
minification, any advanced optimizations (e.g. key crushing), and VM
inconsistencies (both Bun and Safari seem to exclusively use the value
under `displayName` and not `name` in traces for methods defined under
an object's own property...).

We can then find this "common" frame by simply finding the line that has
our special method name (`"DescribeNativeComponentFrameRoot"`), and the
rest of the code to determine the actual component line works as
expected. If by any chance we don't find a frame with our special method
name in either control or sample stack traces, we then revert back to
the existing approach mentioned above by searching for the last line of
the sample frame in the control frame.

## How did you test this change?

1. There are bunch of existing tests that ensure a properly formatted
component trace is logged for certain scenarios, so I ensured the
existing full test suite passed
2. I threw an error in a component that's deep in the component
hierarchy of a large React app (facebook) to ensure there's stack trace
truncation, and ensured the correct component stack trace was logged for
Chrome, Safari, and Firefox, and with and without minification.
3. Ran a large React app (facebook) on the Hermes VM, threw an error in
a component that's deep in the component hierarchy, and ensured that
component frames are generated despite stack traces being truncated in
the middle.

DiffTrain build for [88b00de](88b00de)
kodiakhq bot pushed a commit to vercel/next.js that referenced this pull request Nov 8, 2023
EdisonVan pushed a commit to EdisonVan/react that referenced this pull request Apr 15, 2024
…ook#27132)

## Summary

There's a bug with the existing stack comparison algorithm in
`describeNativeComponentFrame` — specifically how it attempts to find a
common root frame between the control and sample stacks. This PR
attempts to fix that bug by injecting a frame that can have a guaranteed
string in it for us to search for in both stacks to find a common root.

## Brief Background/How it works now

Right now `describeNativeComponentFrame` does the following to leverage
native browser/VM stack frames to get details (e.g. script path, row and
col #s) for a single component:
1. Throwing and catching a control error in the function
2. Calling the component which should eventually throw an error (most of
the time), that we'll catch as our sample error.
3. Diffing the stacks in the control and sample errors to find the line
which should represent our component call.

## What's broken

To account for potential stack trace truncation, the stack diffing
algorithm first attempts to find a common "root" frame by inspecting the
earliest frame of the sample stack and searching for an identical frame
in the control stack starting from the bottom. However, there are a
couple of scenarios which I've hit that cause the above approach to not
work correctly.

First, it's possible that for render passes of extremely large component
trees to have a lot of repeating internal react function calls, which
can result in an incorrect common or "root" frame found. Here's a small
example from a stack trace using React Fizz for SSR.
Our control frame can look like this:
```
Error:
    at Fake (...)
    at construct (native)
    at describeNativeComponentFrame (...)
    at describeClassComponentFrame (...)
    at getStackByComponentStackNode (...)
    at getCurrentStackInDEV (...)
    at renderNodeDestructive (...)
    at renderElement (...)
    at renderNodeDestructiveImpl (...) // <-- Actual common root frame with the sample stack
    at renderNodeDestructive (...)
    at renderElement (...)
    at renderNodeDestructiveImpl (...) // <-- Incorrectly chosen common root frame
    at renderNodeDestructive (...)
```

And our sample stack can look like this:
```
Error:
    at set (...)
    at PureComponent (...)
    at call (native)
    at apply (native)
    at ErrorBoundary (...)
    at construct (native)
    at describeNativeComponentFrame (...)
    at describeClassComponentFrame (...)
    at getStackByComponentStackNode (...)
    at getCurrentStackInDEV (...)
    at renderNodeDestructive (...)
    at renderElement (...)
    at renderNodeDestructiveImpl (...) // <-- Root frame that's common in the control stack
```

Here you can see that the earliest trace in the sample stack, the
`renderNodeDestructiveImpl` call, can exactly match with multiple
`renderNodeDestructiveImpl` calls in the control stack (including file
path and line + col #s). Currently the algorithm will chose the
earliest/last frame with the `renderNodeDestructiveImpl` call (which is
the second last frame in our control stack), which is incorrect. The
actual matching frame in the control stack is the latest or first frame
(when traversing from the top) with the `renderNodeDestructiveImpl`
call. This leads to the rest of the stack diffing associating an
incorrect frame (`at getStackByComponentStackNode (...)`) for the
component.

Another issue with this approach is that it assumes all VMs will
truncate stack traces at the *bottom*, [which isn't the case for the
Hermes
VM](https://github.com/facebook/hermes/blob/df07cf713a84a4434c83c08cede38ba438dc6aca/lib/VM/JSError.cpp#L688-L699)
which **truncates stack traces in the middle**, placing a

```
    at renderNodeDestructiveImpl (...)
    ... skipping {n} frames
    at renderNodeDestructive (...)
```

line in the middle of the stack trace for all stacks that contain more
than 100 traces. This causes stack traces for React Native apps using
the Hermes VM to potentially break for large component trees. Although
for this specific case with Hermes, it's possible to account for this by
either manually grepping and removing the `... skipping` line and
everything below it (see draft PR: facebook#26999), or by implementing the
non-standard `prepareStackTrace` API which Hermes also supports to
manually generate a stack trace that truncates from the bottom ([example
implementation](facebook/react@main...KarimP:react:component-stack-hermes-fix)).

## The Fix

I found different ways to go about fixing this. The first was to search
for a common stack frame starting from the top/latest frame. It's a
relatively small change ([see
implementation](facebook/react@main...KarimP:react:component-stack-fix-2)),
although it is less performant by being n^2 (albeit with `n`
realistically being <= 5 here). It's also a bit more buggy for class
components given that different VMs insert a different amount of
additional lines for new/construct calls...

Another fix would be to actually implement a [longest common
substring](https://en.wikipedia.org/wiki/Longest_common_substring)
algorithm, which can also be roughly n^2 time (assuming the longest
common substring between control and sample will be most of the sample
frame).

The fix I ended up going with was have the lines that throw the control
error and the lines that call/instantiate the component be inside a
distinct method under an object property
(`"DescribeNativeComponentFrameRoot"`). All major VMs (Safari's
JavaScriptCore, Firefox's SpiderMonkey, V8, Hermes, and Bun) should
display the object property name their stack trace. I've also set the
`name` and `displayName` properties for method as well to account for
minification, any advanced optimizations (e.g. key crushing), and VM
inconsistencies (both Bun and Safari seem to exclusively use the value
under `displayName` and not `name` in traces for methods defined under
an object's own property...).

We can then find this "common" frame by simply finding the line that has
our special method name (`"DescribeNativeComponentFrameRoot"`), and the
rest of the code to determine the actual component line works as
expected. If by any chance we don't find a frame with our special method
name in either control or sample stack traces, we then revert back to
the existing approach mentioned above by searching for the last line of
the sample frame in the control frame.

## How did you test this change?

1. There are bunch of existing tests that ensure a properly formatted
component trace is logged for certain scenarios, so I ensured the
existing full test suite passed
2. I threw an error in a component that's deep in the component
hierarchy of a large React app (facebook) to ensure there's stack trace
truncation, and ensured the correct component stack trace was logged for
Chrome, Safari, and Firefox, and with and without minification.
3. Ran a large React app (facebook) on the Hermes VM, threw an error in
a component that's deep in the component hierarchy, and ensured that
component frames are generated despite stack traces being truncated in
the middle.
bigfootjon pushed a commit that referenced this pull request Apr 18, 2024
## Summary

There's a bug with the existing stack comparison algorithm in
`describeNativeComponentFrame` — specifically how it attempts to find a
common root frame between the control and sample stacks. This PR
attempts to fix that bug by injecting a frame that can have a guaranteed
string in it for us to search for in both stacks to find a common root.

## Brief Background/How it works now

Right now `describeNativeComponentFrame` does the following to leverage
native browser/VM stack frames to get details (e.g. script path, row and
col #s) for a single component:
1. Throwing and catching a control error in the function
2. Calling the component which should eventually throw an error (most of
the time), that we'll catch as our sample error.
3. Diffing the stacks in the control and sample errors to find the line
which should represent our component call.

## What's broken

To account for potential stack trace truncation, the stack diffing
algorithm first attempts to find a common "root" frame by inspecting the
earliest frame of the sample stack and searching for an identical frame
in the control stack starting from the bottom. However, there are a
couple of scenarios which I've hit that cause the above approach to not
work correctly.

First, it's possible that for render passes of extremely large component
trees to have a lot of repeating internal react function calls, which
can result in an incorrect common or "root" frame found. Here's a small
example from a stack trace using React Fizz for SSR.
Our control frame can look like this:
```
Error:
    at Fake (...)
    at construct (native)
    at describeNativeComponentFrame (...)
    at describeClassComponentFrame (...)
    at getStackByComponentStackNode (...)
    at getCurrentStackInDEV (...)
    at renderNodeDestructive (...)
    at renderElement (...)
    at renderNodeDestructiveImpl (...) // <-- Actual common root frame with the sample stack
    at renderNodeDestructive (...)
    at renderElement (...)
    at renderNodeDestructiveImpl (...) // <-- Incorrectly chosen common root frame
    at renderNodeDestructive (...)
```

And our sample stack can look like this:
```
Error:
    at set (...)
    at PureComponent (...)
    at call (native)
    at apply (native)
    at ErrorBoundary (...)
    at construct (native)
    at describeNativeComponentFrame (...)
    at describeClassComponentFrame (...)
    at getStackByComponentStackNode (...)
    at getCurrentStackInDEV (...)
    at renderNodeDestructive (...)
    at renderElement (...)
    at renderNodeDestructiveImpl (...) // <-- Root frame that's common in the control stack
```

Here you can see that the earliest trace in the sample stack, the
`renderNodeDestructiveImpl` call, can exactly match with multiple
`renderNodeDestructiveImpl` calls in the control stack (including file
path and line + col #s). Currently the algorithm will chose the
earliest/last frame with the `renderNodeDestructiveImpl` call (which is
the second last frame in our control stack), which is incorrect. The
actual matching frame in the control stack is the latest or first frame
(when traversing from the top) with the `renderNodeDestructiveImpl`
call. This leads to the rest of the stack diffing associating an
incorrect frame (`at getStackByComponentStackNode (...)`) for the
component.

Another issue with this approach is that it assumes all VMs will
truncate stack traces at the *bottom*, [which isn't the case for the
Hermes
VM](https://github.com/facebook/hermes/blob/df07cf713a84a4434c83c08cede38ba438dc6aca/lib/VM/JSError.cpp#L688-L699)
which **truncates stack traces in the middle**, placing a

```
    at renderNodeDestructiveImpl (...)
    ... skipping {n} frames
    at renderNodeDestructive (...)
```

line in the middle of the stack trace for all stacks that contain more
than 100 traces. This causes stack traces for React Native apps using
the Hermes VM to potentially break for large component trees. Although
for this specific case with Hermes, it's possible to account for this by
either manually grepping and removing the `... skipping` line and
everything below it (see draft PR: #26999), or by implementing the
non-standard `prepareStackTrace` API which Hermes also supports to
manually generate a stack trace that truncates from the bottom ([example
implementation](main...KarimP:react:component-stack-hermes-fix)).

## The Fix

I found different ways to go about fixing this. The first was to search
for a common stack frame starting from the top/latest frame. It's a
relatively small change ([see
implementation](main...KarimP:react:component-stack-fix-2)),
although it is less performant by being n^2 (albeit with `n`
realistically being <= 5 here). It's also a bit more buggy for class
components given that different VMs insert a different amount of
additional lines for new/construct calls...

Another fix would be to actually implement a [longest common
substring](https://en.wikipedia.org/wiki/Longest_common_substring)
algorithm, which can also be roughly n^2 time (assuming the longest
common substring between control and sample will be most of the sample
frame).

The fix I ended up going with was have the lines that throw the control
error and the lines that call/instantiate the component be inside a
distinct method under an object property
(`"DescribeNativeComponentFrameRoot"`). All major VMs (Safari's
JavaScriptCore, Firefox's SpiderMonkey, V8, Hermes, and Bun) should
display the object property name their stack trace. I've also set the
`name` and `displayName` properties for method as well to account for
minification, any advanced optimizations (e.g. key crushing), and VM
inconsistencies (both Bun and Safari seem to exclusively use the value
under `displayName` and not `name` in traces for methods defined under
an object's own property...).

We can then find this "common" frame by simply finding the line that has
our special method name (`"DescribeNativeComponentFrameRoot"`), and the
rest of the code to determine the actual component line works as
expected. If by any chance we don't find a frame with our special method
name in either control or sample stack traces, we then revert back to
the existing approach mentioned above by searching for the last line of
the sample frame in the control frame.

## How did you test this change?

1. There are bunch of existing tests that ensure a properly formatted
component trace is logged for certain scenarios, so I ensured the
existing full test suite passed
2. I threw an error in a component that's deep in the component
hierarchy of a large React app (facebook) to ensure there's stack trace
truncation, and ensured the correct component stack trace was logged for
Chrome, Safari, and Firefox, and with and without minification.
3. Ran a large React app (facebook) on the Hermes VM, threw an error in
a component that's deep in the component hierarchy, and ensured that
component frames are generated despite stack traces being truncated in
the middle.

DiffTrain build for commit 88b00de.
henriettelienrebnor pushed a commit to equinor/Dexpi2Imf that referenced this pull request Apr 23, 2025
![snyk-top-banner](https://res.cloudinary.com/snyk/image/upload/r-d/scm-platform/snyk-pull-requests/pr-banner-default.svg)


<h3>Snyk has created this PR to upgrade react from 19.0.0 to
19.1.0.</h3>

:information_source: Keep your dependencies up-to-date. This makes it
easier to fix existing vulnerabilities and to more quickly identify and
fix newly disclosed vulnerabilities when they affect your project.

<hr/>


- The recommended version is **78 versions** ahead of your current
version.

- The recommended version was released **22 days ago**.



<details>
<summary><b>Release notes</b></summary>
<br/>
  <details>
    <summary>Package name: <b>react</b></summary>
    <ul>
      <li>
<b>19.1.0</b> - <a
href="https://redirect.github.com/facebook/react/releases/tag/v19.1.0">2025-03-28</a></br><h3>Owner
Stack</h3>
<p>An Owner Stack is a string representing the components that are
directly responsible for rendering a particular component. You can log
Owner Stacks when debugging or use Owner Stacks to enhance error
overlays or other development tools. Owner Stacks are only available in
development builds. Component Stacks in production are unchanged.</p>
<ul>
<li>An Owner Stack is a development-only stack trace that helps identify
which components are responsible for rendering a particular component.
An Owner Stack is distinct from a Component Stacks, which shows the
hierarchy of components leading to an error.</li>
<li>The <a href="https://react.dev/reference/react/captureOwnerStack"
rel="nofollow">captureOwnerStack API</a> is only available in
development mode and returns a Owner Stack, if available. The API can be
used to enhance error overlays or log component relationships when
debugging. <a
href="https://redirect.github.com/facebook/react/pull/29923"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/29923/hovercard">#29923</a>, <a
href="https://redirect.github.com/facebook/react/pull/32353"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/32353/hovercard">#32353</a>, <a
href="https://redirect.github.com/facebook/react/pull/30306"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/30306/hovercard">#30306</a>,<br>
<a href="https://redirect.github.com/facebook/react/pull/32538"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/32538/hovercard">#32538</a>, <a
href="https://redirect.github.com/facebook/react/pull/32529"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/32529/hovercard">#32529</a>, <a
href="https://redirect.github.com/facebook/react/pull/32538"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/32538/hovercard">#32538</a></li>
</ul>
<h3>React</h3>
<ul>
<li>Enhanced support for Suspense boundaries to be used anywhere,
including the client, server, and during hydration. <a
href="https://redirect.github.com/facebook/react/pull/32069"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/32069/hovercard">#32069</a>, <a
href="https://redirect.github.com/facebook/react/pull/32163"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/32163/hovercard">#32163</a>, <a
href="https://redirect.github.com/facebook/react/pull/32224"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/32224/hovercard">#32224</a>, <a
href="https://redirect.github.com/facebook/react/pull/32252"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/32252/hovercard">#32252</a></li>
<li>Reduced unnecessary client rendering through improved hydration
scheduling <a
href="https://redirect.github.com/facebook/react/pull/31751"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/31751/hovercard">#31751</a></li>
<li>Increased priority of client rendered Suspense boundaries <a
href="https://redirect.github.com/facebook/react/pull/31776"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/31776/hovercard">#31776</a></li>
<li>Fixed frozen fallback states by rendering unfinished Suspense
boundaries on the client. <a
href="https://redirect.github.com/facebook/react/pull/31620"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/31620/hovercard">#31620</a></li>
<li>Reduced garbage collection pressure by improving Suspense boundary
retries. <a href="https://redirect.github.com/facebook/react/pull/31667"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/31667/hovercard">#31667</a></li>
<li>Fixed erroneous “Waiting for Paint” log when the passive effect
phase was not delayed <a
href="https://redirect.github.com/facebook/react/pull/31526"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/31526/hovercard">#31526</a></li>
<li>Fixed a regression causing key warnings for flattened positional
children in development mode. <a
href="https://redirect.github.com/facebook/react/pull/32117"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/32117/hovercard">#32117</a></li>
<li>Updated <code>useId</code> to use valid CSS selectors, changing
format from <code>:r123:</code> to <code>«r123»</code>. <a
href="https://redirect.github.com/facebook/react/pull/32001"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/32001/hovercard">#32001</a></li>
<li>Added a dev-only warning for null/undefined created in useEffect,
useInsertionEffect, and useLayoutEffect. <a
href="https://redirect.github.com/facebook/react/pull/32355"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/32355/hovercard">#32355</a></li>
<li>Fixed a bug where dev-only methods were exported in production
builds. React.act is no longer available in production builds. <a
href="https://redirect.github.com/facebook/react/pull/32200"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/32200/hovercard">#32200</a></li>
<li>Improved consistency across prod and dev to improve compatibility
with Google Closure Complier and bindings <a
href="https://redirect.github.com/facebook/react/pull/31808"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/31808/hovercard">#31808</a></li>
<li>Improve passive effect scheduling for consistent task yielding. <a
href="https://redirect.github.com/facebook/react/pull/31785"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/31785/hovercard">#31785</a></li>
<li>Fixed asserts in React Native when
passChildrenWhenCloningPersistedNodes is enabled for OffscreenComponent
rendering. <a
href="https://redirect.github.com/facebook/react/pull/32528"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/32528/hovercard">#32528</a></li>
<li>Fixed component name resolution for Portal <a
href="https://redirect.github.com/facebook/react/pull/32640"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/32640/hovercard">#32640</a></li>
<li>Added support for beforetoggle and toggle events on the dialog
element. <a class="issue-link js-issue-link" data-error-text="Failed to
load title" data-id="2882132160" data-permission-text="Title is private"
data-url="https://github.com/facebook/react/issues/32479"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/32479/hovercard"
href="https://redirect.github.com/facebook/react/pull/32479">#32479</a>
<a href="https://redirect.github.com/facebook/react/pull/32479"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/32479/hovercard">#32479</a></li>
</ul>
<h3>React DOM</h3>
<ul>
<li>Fixed double warning when the <code>href</code> attribute is an
empty string <a
href="https://redirect.github.com/facebook/react/pull/31783"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/31783/hovercard">#31783</a></li>
<li>Fixed an edge case where <code>getHoistableRoot()</code> didn’t work
properly when the container was a Document <a
href="https://redirect.github.com/facebook/react/pull/32321"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/32321/hovercard">#32321</a></li>
<li>Removed support for using HTML comments (e.g. <code>&lt;!--
--&gt;</code>) as a DOM container. <a
href="https://redirect.github.com/facebook/react/pull/32250"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/32250/hovercard">#32250</a></li>
<li>Added support for <code>&lt;script&gt;</code> and
<code>&lt;template&gt;</code> tags to be nested within
<code>&lt;select&gt;</code> tags. <a
href="https://redirect.github.com/facebook/react/pull/31837"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/31837/hovercard">#31837</a></li>
<li>Fixed responsive images to be preloaded as HTML instead of headers
<a href="https://redirect.github.com/facebook/react/pull/32445"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/32445/hovercard">#32445</a></li>
</ul>
<h3>use-sync-external-store</h3>
<ul>
<li>Added <code>exports</code> field to <code>package.json</code> for
<code>use-sync-external-store</code> to support various entrypoints. <a
href="https://redirect.github.com/facebook/react/pull/25231"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/25231/hovercard">#25231</a></li>
</ul>
<h3>React Server Components</h3>
<ul>
<li>Added <code>unstable_prerender</code>, a new experimental API for
prerendering React Server Components on the server <a
href="https://redirect.github.com/facebook/react/pull/31724"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/31724/hovercard">#31724</a></li>
<li>Fixed an issue where streams would hang when receiving new chunks
after a global error <a
href="https://redirect.github.com/facebook/react/pull/31840"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/31840/hovercard">#31840</a>, <a
href="https://redirect.github.com/facebook/react/pull/31851"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/31851/hovercard">#31851</a></li>
<li>Fixed an issue where pending chunks were counted twice. <a
href="https://redirect.github.com/facebook/react/pull/31833"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/31833/hovercard">#31833</a></li>
<li>Added support for streaming in edge environments <a
href="https://redirect.github.com/facebook/react/pull/31852"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/31852/hovercard">#31852</a></li>
<li>Added support for sending custom error names from a server so that
they are available in the client for console replaying. <a
href="https://redirect.github.com/facebook/react/pull/32116"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/32116/hovercard">#32116</a></li>
<li>Updated the server component wire format to remove IDs for hints and
console.log because they have no return value <a
href="https://redirect.github.com/facebook/react/pull/31671"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/31671/hovercard">#31671</a></li>
<li>Exposed <code>registerServerReference</code> in client builds to
handle server references in different environments. <a
href="https://redirect.github.com/facebook/react/pull/32534"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/32534/hovercard">#32534</a></li>
<li>Added react-server-dom-parcel package which integrates Server
Components with the <a href="https://parceljs.org/"
rel="nofollow">Parcel bundler</a> <a
href="https://redirect.github.com/facebook/react/pull/31725"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/31725/hovercard">#31725</a>, <a
href="https://redirect.github.com/facebook/react/pull/32132"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/32132/hovercard">#32132</a>, <a
href="https://redirect.github.com/facebook/react/pull/31799"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/31799/hovercard">#31799</a>, <a
href="https://redirect.github.com/facebook/react/pull/32294"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/32294/hovercard">#32294</a>, <a
href="https://redirect.github.com/facebook/react/pull/31741"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/31741/hovercard">#31741</a></li>
</ul>
      </li>
      <li>
        <b>19.1.0-canary-ff628334-20250205</b> - 2025-02-06
      </li>
      <li>
        <b>19.1.0-canary-fcb4e0f1-20250219</b> - 2025-02-20
      </li>
      <li>
        <b>19.1.0-canary-fc8a898d-20241226</b> - 2024-12-27
      </li>
      <li>
        <b>19.1.0-canary-fbcda19a-20250317</b> - 2025-03-17
      </li>
      <li>
        <b>19.1.0-canary-f9d78089-20250306</b> - 2025-03-07
      </li>
      <li>
        <b>19.1.0-canary-f83903bf-20250212</b> - 2025-02-12
      </li>
      <li>
        <b>19.1.0-canary-f457d0b4-20250313</b> - 2025-03-13
      </li>
      <li>
        <b>19.1.0-canary-f0edf41e-20250115</b> - 2025-01-14
      </li>
      <li>
        <b>19.1.0-canary-ef979d47-20241218</b> - 2024-12-18
      </li>
      <li>
        <b>19.1.0-canary-ef4bc8b4-20250328</b> - 2025-03-28
      </li>
      <li>
        <b>19.1.0-canary-ebc22ef7-20250225</b> - 2025-02-26
      </li>
      <li>
        <b>19.1.0-canary-e670e72f-20250214</b> - 2025-02-14
      </li>
      <li>
        <b>19.1.0-canary-e1e74071-20250321</b> - 2025-03-21
      </li>
      <li>
        <b>19.1.0-canary-e06c72fc-20241215</b> - 2024-12-16
      </li>
      <li>
        <b>19.1.0-canary-e03ac20f-20250305</b> - 2025-03-05
      </li>
      <li>
        <b>19.1.0-canary-de82912e-20241220</b> - 2024-12-20
      </li>
      <li>
        <b>19.1.0-canary-de1eaa26-20250124</b> - 2025-01-24
      </li>
      <li>
        <b>19.1.0-canary-db7dfe05-20250319</b> - 2025-03-19
      </li>
      <li>
        <b>19.1.0-canary-d85cf3e5-20250205</b> - 2025-02-05
      </li>
      <li>
        <b>19.1.0-canary-d55cc79b-20250228</b> - 2025-02-28
      </li>
      <li>
        <b>19.1.0-canary-d46b04a2-20250117</b> - 2025-01-17
      </li>
      <li>
        <b>19.1.0-canary-d4287258-20241217</b> - 2024-12-17
      </li>
      <li>
        <b>19.1.0-canary-d331ba04-20250307</b> - 2025-03-10
      </li>
      <li>
        <b>19.1.0-canary-cd90a4d8-20250210</b> - 2025-02-11
      </li>
      <li>
        <b>19.1.0-canary-cbbe8666-20250213</b> - 2025-02-13
      </li>
      <li>
        <b>19.1.0-canary-cabd8a0e-20250113</b> - 2025-01-13
      </li>
      <li>
        <b>19.1.0-canary-c69a5fc5-20250318</b> - 2025-03-18
      </li>
      <li>
        <b>19.1.0-canary-c492f975-20250128</b> - 2025-01-29
      </li>
      <li>
        <b>19.1.0-canary-c01b8058-20241229</b> - 2024-12-30
      </li>
      <li>
        <b>19.1.0-canary-bb9a24d9-20250130</b> - 2025-01-30
      </li>
      <li>
        <b>19.1.0-canary-b3a95caf-20250113</b> - 2025-01-14
      </li>
      <li>
        <b>19.1.0-canary-b158439a-20250115</b> - 2025-01-15
      </li>
      <li>
        <b>19.1.0-canary-ae9017ce-20250122</b> - 2025-01-23
      </li>
      <li>
        <b>19.1.0-canary-a84862db-20250218</b> - 2025-02-19
      </li>
      <li>
        <b>19.1.0-canary-a4f9bd58-20250319</b> - 2025-03-20
      </li>
      <li>
        <b>19.1.0-canary-a4b2d0d5-20250203</b> - 2025-02-03
      </li>
      <li>
        <b>19.1.0-canary-9ff42a87-20250130</b> - 2025-01-31
      </li>
      <li>
        <b>19.1.0-canary-9eabb373-20250124</b> - 2025-01-27
      </li>
      <li>
        <b>19.1.0-canary-9b62ee71-20250122</b> - 2025-01-22
      </li>
      <li>
        <b>19.1.0-canary-97d79495-20241223</b> - 2024-12-24
      </li>
      <li>
        <b>19.1.0-canary-9463d51e-20241219</b> - 2024-12-19
      </li>
      <li>
        <b>19.1.0-canary-93b58361-20250209</b> - 2025-02-10
      </li>
      <li>
        <b>19.1.0-canary-8a7b487e-20250218</b> - 2025-02-18
      </li>
      <li>
        <b>19.1.0-canary-8759c5c8-20250207</b> - 2025-02-07
      </li>
      <li>
        <b>19.1.0-canary-7eb8234f-20241218</b> - 2024-12-18
      </li>
      <li>
        <b>19.1.0-canary-7b402084-20250107</b> - 2025-01-07
      </li>
      <li>
        <b>19.1.0-canary-74ea0c73-20250109</b> - 2025-01-09
      </li>
      <li>
        <b>19.1.0-canary-740a4f7a-20250325</b> - 2025-03-25
      </li>
      <li>
        <b>19.1.0-canary-7130d0c6-20241212</b> - 2024-12-12
      </li>
      <li>
        <b>19.1.0-canary-6aa8254b-20250312</b> - 2025-03-12
      </li>
      <li>
        <b>19.1.0-canary-694d3e1a-20241231</b> - 2025-01-01
      </li>
      <li>
        <b>19.1.0-canary-6907aa2a-20241220</b> - 2024-12-23
      </li>
      <li>
        <b>19.1.0-canary-662957cc-20250221</b> - 2025-02-21
      </li>
      <li>
        <b>19.1.0-canary-62208bee-20250102</b> - 2025-01-02
      </li>
      <li>
        <b>19.1.0-canary-5b51a2b9-20250116</b> - 2025-01-16
      </li>
      <li>
        <b>19.1.0-canary-540efebc-20250112</b> - 2025-01-12
      </li>
      <li>
        <b>19.1.0-canary-5398b711-20250314</b> - 2025-03-14
      </li>
      <li>
        <b>19.1.0-canary-518d06d2-20241219</b> - 2024-12-19
      </li>
      <li>
        <b>19.1.0-canary-4dff0e62-20241213</b> - 2024-12-13
      </li>
      <li>
        <b>19.1.0-canary-4632e36a-20250216</b> - 2025-02-17
      </li>
      <li>
        <b>19.1.0-canary-443b7ff2-20250303</b> - 2025-03-04
      </li>
      <li>
        <b>19.1.0-canary-4280563b-20250326</b> - 2025-03-27
      </li>
      <li>
        <b>19.1.0-canary-42687267-20250108</b> - 2025-01-08
      </li>
      <li>
        <b>19.1.0-canary-3ce77d55-20250106</b> - 2025-01-06
      </li>
      <li>
        <b>19.1.0-canary-3b009b4c-20250102</b> - 2025-01-03
      </li>
      <li>
        <b>19.1.0-canary-37906d4d-20250127</b> - 2025-01-28
      </li>
      <li>
        <b>19.1.0-canary-32b0cad8-20250213</b> - 2025-02-13
      </li>
      <li>
        <b>19.1.0-canary-313332d1-20250326</b> - 2025-03-26
      </li>
      <li>
        <b>19.1.0-canary-2980f277-20250301</b> - 2025-03-03
      </li>
      <li>
        <b>19.1.0-canary-25677265-20250224</b> - 2025-02-24
      </li>
      <li>
        <b>19.1.0-canary-22e39ea7-20250225</b> - 2025-02-25
      </li>
      <li>
        <b>19.1.0-canary-18eaf51b-20250118</b> - 2025-01-20
      </li>
      <li>
        <b>19.1.0-canary-130095f7-20241212</b> - 2024-12-12
      </li>
      <li>
        <b>19.1.0-canary-0ca3deeb-20250311</b> - 2025-03-11
      </li>
      <li>
        <b>19.1.0-canary-0a82580b-20250203</b> - 2025-02-04
      </li>
      <li>
        <b>19.1.0-canary-056073de-20250109</b> - 2025-01-10
      </li>
      <li>
        <b>19.1.0-canary-029e8bd6-20250306</b> - 2025-03-06
      </li>
      <li>
<b>19.0.0</b> - <a
href="https://redirect.github.com/facebook/react/releases/tag/v19.0.0">2024-12-05</a></br><p>Below
is a list of all new features, APIs, deprecations, and breaking changes.
Read <a href="https://react.dev/blog/2024/04/25/react-19"
rel="nofollow">React 19 release post</a> and <a
href="https://react.dev/blog/2024/04/25/react-19-upgrade-guide"
rel="nofollow">React 19 upgrade guide</a> for more information.</p>
<blockquote>
<p>Note: To help make the upgrade to React 19 easier, we’ve published a
react@18.3 release that is identical to 18.2 but adds warnings for
deprecated APIs and other changes that are needed for React 19. We
recommend upgrading to React 18.3.1 first to help identify any issues
before upgrading to React 19.</p>
</blockquote>
<h2>New Features</h2>
<h3>React</h3>
<ul>
<li>Actions: <code>startTransition</code> can now accept async
functions. Functions passed to <code>startTransition</code> are called
“Actions”. A given Transition can include one or more Actions which
update state in the background and update the UI with one commit. In
addition to updating state, Actions can now perform side effects
including async requests, and the Action will wait for the work to
finish before finishing the Transition. This feature allows Transitions
to include side effects like <code>fetch()</code> in the pending state,
and provides support for error handling, and optimistic updates.</li>
<li><code>useActionState</code>: is a new hook to order Actions inside
of a Transition with access to the state of the action, and the pending
state. It accepts a reducer that can call Actions, and the initial state
used for first render. It also accepts an optional string that is used
if the action is passed to a form <code>action</code> prop to support
progressive enhancement in forms.</li>
<li><code>useOptimistic</code>: is a new hook to update state while a
Transition is in progress. It returns the state, and a set function that
can be called inside a transition to “optimistically” update the state
to expected final value immediately while the Transition completes in
the background. When the transition finishes, the state is updated to
the new value.</li>
<li><code>use</code>: is a new API that allows reading resources in
render. In React 19, <code>use</code> accepts a promise or Context. If
provided a promise, <code>use</code> will suspend until a value is
resolved. <code>use</code> can only be used in render but can be called
conditionally.</li>
<li><code>ref</code> as a prop: Refs can now be used as props, removing
the need for <code>forwardRef</code>.</li>
<li><strong>Suspense sibling pre-warming</strong>: When a component
suspends, React will immediately commit the fallback of the nearest
Suspense boundary, without waiting for the entire sibling tree to
render. After the fallback commits, React will schedule another render
for the suspended siblings to “pre-warm” lazy requests.</li>
</ul>
<h3>React DOM Client</h3>
<ul>
<li><code>&lt;form&gt; action</code> prop: Form Actions allow you to
manage forms automatically and integrate with
<code>useFormStatus</code>. When a <code>&lt;form&gt; action</code>
succeeds, React will automatically reset the form for uncontrolled
components. The form can be reset manually with the new
<code>requestFormReset</code> API.</li>
<li><code>&lt;button&gt; and &lt;input&gt; formAction</code> prop:
Actions can be passed to the <code>formAction</code> prop to configure
form submission behavior. This allows using different Actions depending
on the input.</li>
<li><code>useFormStatus</code>: is a new hook that provides the status
of the parent <code>&lt;form&gt; action</code>, as if the form was a
Context provider. The hook returns the values: <code>pending</code>,
<code>data</code>, <code>method</code>, and <code>action</code>.</li>
<li>Support for Document Metadata: We’ve added support for rendering
document metadata tags in components natively. React will automatically
hoist them into the <code>&lt;head&gt;</code> section of the
document.</li>
<li>Support for Stylesheets: React 19 will ensure stylesheets are
inserted into the <code>&lt;head&gt;</code> on the client before
revealing the content of a Suspense boundary that depends on that
stylesheet.</li>
<li>Support for async scripts: Async scripts can be rendered anywhere in
the component tree and React will handle ordering and
deduplication.</li>
<li>Support for preloading resources: React 19 ships with
<code>preinit</code>, <code>preload</code>, <code>prefetchDNS</code>,
and <code>preconnect</code> APIs to optimize initial page loads by
moving discovery of additional resources like fonts out of stylesheet
loading. They can also be used to prefetch resources used by an
anticipated navigation.</li>
</ul>
<h3>React DOM Server</h3>
<ul>
<li>Added <code>prerender</code> and <code>prerenderToNodeStream</code>
APIs for static site generation. They are designed to work with
streaming environments like Node.js Streams and Web Streams. Unlike
<code>renderToString</code>, they wait for data to load for HTML
generation.</li>
</ul>
<h3>React Server Components</h3>
<ul>
<li>RSC features such as directives, server components, and server
functions are now stable. This means libraries that ship with Server
Components can now target React 19 as a peer dependency with a
react-server export condition for use in frameworks that support the
Full-stack React Architecture. The underlying APIs used to implement a
React Server Components bundler or framework do not follow semver and
may break between minors in React 19.x. See <a
href="https://19.react.dev/reference/rsc/server-components"
rel="nofollow">docs</a> for how to support React Server Components.</li>
</ul>
<h2>Deprecations</h2>
<ul>
<li>Deprecated: <code>element.ref</code> access: React 19 supports ref
as a prop, so we’re deprecating <code>element.ref</code> in favor of
<code>element.props.ref</code>. Accessing will result in a warning.</li>
<li><code>react-test-renderer</code>: In React 19, react-test-renderer
logs a deprecation warning and has switched to concurrent rendering for
web usage. We recommend migrating your tests to @
testinglibrary.com/docs/react-testing-library/intro/) or @
testingesting-library.com/docs/react-native-testing-library/intro)</li>
</ul>
<h2>Breaking Changes</h2>
<p>React 19 brings in a number of breaking changes, including the
removals of long-deprecated APIs. We recommend first upgrading to
<code>18.3.1</code>, where we've added additional deprecation warnings.
Check out the <a
href="https://19.react.dev/blog/2024/04/25/react-19-upgrade-guide"
rel="nofollow">upgrade guide</a> for more details and guidance on
codemodding.</p>
<h3>React</h3>
<ul>
<li>New JSX Transform is now required: We introduced <a
href="https://legacy.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html"
rel="nofollow">a new JSX transform</a> in 2020 to improve bundle size
and use JSX without importing React. In React 19, we’re adding
additional improvements like using ref as a prop and JSX speed
improvements that require the new transform.</li>
<li>Errors in render are not re-thrown: Errors that are not caught by an
Error Boundary are now reported to window.reportError. Errors that are
caught by an Error Boundary are reported to console.error. We’ve
introduced <code>onUncaughtError</code> and <code>onCaughtError</code>
methods to <code>createRoot</code> and <code>hydrateRoot</code> to
customize this error handling.</li>
<li>Removed: <code>propTypes</code>: Using <code>propTypes</code> will
now be silently ignored. If required, we recommend migrating to
TypeScript or another type-checking solution.</li>
<li>Removed: <code>defaultProps</code> for functions: ES6 default
parameters can be used in place. Class components continue to support
<code>defaultProps</code> since there is no ES6 alternative.</li>
<li>Removed: <code>contextTypes</code> and <code>getChildContext</code>:
Legacy Context for class components has been removed in favor of the
<code>contextType</code> API.</li>
<li>Removed: string refs: Any usage of string refs need to be migrated
to ref callbacks.</li>
<li>Removed: Module pattern factories: A rarely used pattern that can be
migrated to regular functions.</li>
<li>Removed: <code>React.createFactory</code>: Now that JSX is broadly
supported, all <code>createFactory</code> usage can be migrated to JSX
components.</li>
<li>Removed: <code>react-test-renderer/shallow</code>: This has been a
re-export of <a
href="https://redirect.github.com/enzymejs/react-shallow-renderer">react-shallow-renderer</a>
since React 18. If needed, you can continue to use the third-party
package directly. We recommend using @
testinglibrary.com/docs/react-testing-library/intro/) or @
testingesting-library.com/docs/react-native-testing-library/intro)
instead.</li>
</ul>
<h3>React DOM</h3>
<ul>
<li>Removed: <code>react-dom/test-utils</code>: We’ve moved
<code>act</code> from <code>react-dom/test-utils</code> to react. All
other utilities have been removed.</li>
<li>Removed: <code>ReactDOM</code>.<code>render</code>,
<code>ReactDOM</code>.<code>hydrate</code>: These have been removed in
favor of the concurrent equivalents:
<code>ReactDOM</code>.<code>createRoot</code> and
<code>ReactDOM.hydrateRoot</code>.</li>
<li>Removed: <code>unmountComponentAtNode</code>: Removed in favor of
<code>root.unmount()</code>.</li>
<li>Removed: <code>ReactDOM</code>.<code>findDOMNode</code>: You can
replace <code>ReactDOM</code>.<code>findDOMNode</code> with DOM
Refs.</li>
</ul>
<h2>Notable Changes</h2>
<h3>React</h3>
<ul>
<li><code>&lt;Context&gt;</code> as a provider: You can now render
<code>&lt;Context&gt;</code> as a provider instead of
<code>&lt;Context.Provider&gt;</code>.</li>
<li>Cleanup functions for refs: When the component unmounts, React will
call the cleanup function returned from the ref callback.</li>
<li><code>useDeferredValue</code> initial value argument: When provided,
<code>useDeferredValue</code> will return the initial value for the
initial render of a component, then schedule a re-render in the
background with the <code>deferredValue</code> returned.</li>
<li>Support for Custom Elements: React 19 now passes all tests on <a
href="https://custom-elements-everywhere.com/" rel="nofollow">Custom
Elements Everywhere</a>.</li>
<li>StrictMode changes: <code>useMemo</code> and
<code>useCallback</code> will now reuse the memoized results from the
first render, during the second render. Additionally, StrictMode will
now double-invoke ref callback functions on initial mount.</li>
<li>UMD builds removed: To load React 19 with a script tag, we recommend
using an ESM-based CDN such as <a href="http://esm.sh"
rel="nofollow">esm.sh</a>.</li>
</ul>
<h3>React DOM</h3>
<ul>
<li>Diffs for hydration errors: In the case of a mismatch, React 19 logs
a single error with a diff of the mismatched content.</li>
<li>Compatibility with third-party scripts and extensions: React will
now force a client re-render to fix up any mismatched content caused by
elements inserted by third-party JS.</li>
</ul>
<h2>TypeScript Changes</h2>
<p>The most common changes can be codemodded with <code>npx
types-react-codemod@latest preset-19
./path-to-your-react-ts-files</code>.</p>
<ul>
<li>Removed deprecated TypeScript types:
<ul>
<li><code>ReactChild</code> (replacement: <code>React.ReactElement |
number | string)</code></li>
<li><code>ReactFragment</code> (replacement:
<code>Iterable&lt;React.ReactNode&gt;</code>)</li>
<li><code>ReactNodeArray</code> (replacement:
<code>ReadonlyArray&lt;React.ReactNode&gt;</code>)</li>
<li><code>ReactText</code> (replacement: <code>number |
string</code>)</li>
<li><code>VoidFunctionComponent</code> (replacement:
<code>FunctionComponent</code>)</li>
<li><code>VFC</code> (replacement: <code>FC</code>)</li>
<li>Moved to <code>prop-types</code>: <code>Requireable</code>,
<code>ValidationMap</code>, <code>Validator</code>,
<code>WeakValidationMap</code></li>
<li>Moved to <code>create-react-class</code>:
<code>ClassicComponentClass</code>, <code>ClassicComponent</code>,
<code>ClassicElement</code>, <code>ComponentSpec</code>,
<code>Mixin</code>, <code>ReactChildren</code>, <code>ReactHTML</code>,
<code>ReactSVG</code>, <code>SFCFactory</code></li>
</ul>
</li>
<li>Disallow implicit return in refs: refs can now accept cleanup
functions. When you return something else, we can’t tell if you
intentionally returned something not meant to clean up or returned the
wrong value. Implicit returns of anything but functions will now
error.</li>
<li>Require initial argument to <code>useRef</code>: The initial
argument is now required to match <code>useState</code>,
<code>createContext</code> etc</li>
<li>Refs are mutable by default: Ref objects returned from
<code>useRef()</code> are now always mutable instead of sometimes being
immutable. This feature was too confusing for users and conflicted with
legit cases where refs were managed by React and manually written
to.</li>
<li>Strict <code>ReactElement</code> typing: The props of React elements
now default to <code>unknown</code> instead of <code>any</code> if the
element is typed as <code>ReactElement</code></li>
<li>JSX namespace in TypeScript: The global <code>JSX</code> namespace
is removed to improve interoperability with other libraries using JSX.
Instead, the JSX namespace is available from the React package:
<code>import { JSX } from 'react'</code></li>
<li>Better <code>useReducer</code> typings: Most <code>useReducer</code>
usage should not require explicit type arguments.<br>
For example,
<div class="highlight highlight-source-diff notranslate
position-relative overflow-auto"
data-snippet-clipboard-copy-content="-useReducer&lt;React.Reducer&lt;State,
Action&gt;&gt;(reducer)
+useReducer(reducer) "><pre><span class="pl-md"><span
class="pl-md">-</span>useReducer&lt;React.Reducer&lt;State,
Action&gt;&gt;(reducer) </span>
<span class="pl-mi1"><span class="pl-mi1">+</span>useReducer(reducer)
</span></pre></div>
or
<div class="highlight highlight-source-diff notranslate
position-relative overflow-auto"
data-snippet-clipboard-copy-content="-useReducer&lt;React.Reducer&lt;State,
Action&gt;&gt;(reducer)
+useReducer&lt;State, [Action]&gt;(reducer)"><pre><span
class="pl-md"><span
class="pl-md">-</span>useReducer&lt;React.Reducer&lt;State,
Action&gt;&gt;(reducer) </span>
<span class="pl-mi1"><span class="pl-mi1">+</span>useReducer&lt;State,
[Action]&gt;(reducer)</span></pre></div>
</li>
</ul>
<h2>All Changes</h2>
<h3>React</h3>
<ul>
<li>Add support for async Actions (<a
href="https://redirect.github.com/facebook/react/pull/26621"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/26621/hovercard">#26621</a>, <a
href="https://redirect.github.com/facebook/react/pull/26726"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/26726/hovercard">#26726</a>, <a
href="https://redirect.github.com/facebook/react/pull/28078"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/28078/hovercard">#28078</a>, <a
href="https://redirect.github.com/facebook/react/pull/28097"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/28097/hovercard">#28097</a>, <a
href="https://redirect.github.com/facebook/react/pull/29226"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/29226/hovercard">#29226</a>, <a
href="https://redirect.github.com/facebook/react/pull/29618"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/29618/hovercard">#29618</a>, <a
href="https://redirect.github.com/facebook/react/pull/29670"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/29670/hovercard">#29670</a>, <a
href="https://redirect.github.com/facebook/react/pull/26716"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/26716/hovercard">#26716</a> by
<a class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/acdlite/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/acdlite">@ acdlite</a> and <a
class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/sebmarkbage/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/sebmarkbage">@ sebmarkbage</a>)</li>
<li>Add <code>useActionState()</code> hook to update state based on the
result of a Form Action (<a
href="https://redirect.github.com/facebook/react/pull/27270"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/27270/hovercard">#27270</a>, <a
href="https://redirect.github.com/facebook/react/pull/27278"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/27278/hovercard">#27278</a>, <a
href="https://redirect.github.com/facebook/react/pull/27309"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/27309/hovercard">#27309</a>, <a
href="https://redirect.github.com/facebook/react/pull/27302"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/27302/hovercard">#27302</a>, <a
href="https://redirect.github.com/facebook/react/pull/27307"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/27307/hovercard">#27307</a>, <a
href="https://redirect.github.com/facebook/react/pull/27366"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/27366/hovercard">#27366</a>, <a
href="https://redirect.github.com/facebook/react/pull/27370"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/27370/hovercard">#27370</a>, <a
href="https://redirect.github.com/facebook/react/pull/27321"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/27321/hovercard">#27321</a>, <a
href="https://redirect.github.com/facebook/react/pull/27374"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/27374/hovercard">#27374</a>, <a
href="https://redirect.github.com/facebook/react/pull/27372"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/27372/hovercard">#27372</a>, <a
href="https://redirect.github.com/facebook/react/pull/27397"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/27397/hovercard">#27397</a>, <a
href="https://redirect.github.com/facebook/react/pull/27399"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/27399/hovercard">#27399</a>, <a
href="https://redirect.github.com/facebook/react/pull/27460"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/27460/hovercard">#27460</a>, <a
href="https://redirect.github.com/facebook/react/pull/28557"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/28557/hovercard">#28557</a>, <a
href="https://redirect.github.com/facebook/react/pull/27570"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/27570/hovercard">#27570</a>, <a
href="https://redirect.github.com/facebook/react/pull/27571"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/27571/hovercard">#27571</a>, <a
href="https://redirect.github.com/facebook/react/pull/28631"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/28631/hovercard">#28631</a>, <a
href="https://redirect.github.com/facebook/react/pull/28788"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/28788/hovercard">#28788</a>, <a
href="https://redirect.github.com/facebook/react/pull/29694"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/29694/hovercard">#29694</a>, <a
href="https://redirect.github.com/facebook/react/pull/29695"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/29695/hovercard">#29695</a>, <a
href="https://redirect.github.com/facebook/react/pull/29694"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/29694/hovercard">#29694</a>, <a
href="https://redirect.github.com/facebook/react/pull/29665"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/29665/hovercard">#29665</a>, <a
href="https://redirect.github.com/facebook/react/pull/28232"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/28232/hovercard">#28232</a>, <a
href="https://redirect.github.com/facebook/react/pull/28319"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/28319/hovercard">#28319</a> by
<a class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/acdlite/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/acdlite">@ acdlite</a>, <a
class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/eps1lon/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/eps1lon">@ eps1lon</a>, and <a
class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/rickhanlonii/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/rickhanlonii">@ rickhanlonii</a>)</li>
<li>Add <code>use()</code> API to read resources in render (<a
href="https://redirect.github.com/facebook/react/pull/25084"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/25084/hovercard">#25084</a>, <a
href="https://redirect.github.com/facebook/react/pull/25202"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/25202/hovercard">#25202</a>, <a
href="https://redirect.github.com/facebook/react/pull/25207"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/25207/hovercard">#25207</a>, <a
href="https://redirect.github.com/facebook/react/pull/25214"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/25214/hovercard">#25214</a>, <a
href="https://redirect.github.com/facebook/react/pull/25226"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/25226/hovercard">#25226</a>, <a
href="https://redirect.github.com/facebook/react/pull/25247"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/25247/hovercard">#25247</a>, <a
href="https://redirect.github.com/facebook/react/pull/25539"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/25539/hovercard">#25539</a>, <a
href="https://redirect.github.com/facebook/react/pull/25538"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/25538/hovercard">#25538</a>, <a
href="https://redirect.github.com/facebook/react/pull/25537"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/25537/hovercard">#25537</a>, <a
href="https://redirect.github.com/facebook/react/pull/25543"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/25543/hovercard">#25543</a>, <a
href="https://redirect.github.com/facebook/react/pull/25561"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/25561/hovercard">#25561</a>, <a
href="https://redirect.github.com/facebook/react/pull/25620"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/25620/hovercard">#25620</a>, <a
href="https://redirect.github.com/facebook/react/pull/25615"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/25615/hovercard">#25615</a>, <a
href="https://redirect.github.com/facebook/react/pull/25922"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/25922/hovercard">#25922</a>, <a
href="https://redirect.github.com/facebook/react/pull/25641"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/25641/hovercard">#25641</a>, <a
href="https://redirect.github.com/facebook/react/pull/25634"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/25634/hovercard">#25634</a>, <a
href="https://redirect.github.com/facebook/react/pull/26232"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/26232/hovercard">#26232</a>, <a
href="https://redirect.github.com/facebook/react/pull/26535"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/26535/hovercard">#26536</a>, <a
href="https://redirect.github.com/facebook/react/pull/26739"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/26739/hovercard">#26739</a>, <a
href="https://redirect.github.com/facebook/react/pull/28233"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/28233/hovercard">#28233</a> by
<a class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/acdlite/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/acdlite">@ acdlite</a>, <a
class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/mofeiZ/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/mofeiZ">@ mofeiZ</a>, <a
class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/sebmarkbage/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/sebmarkbage">@ sebmarkbage</a>, <a
class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/sophiebits/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/sophiebits">@ sophiebits</a>, <a
class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/eps1lon/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/eps1lon">@ eps1lon</a>, and <a
class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/hansottowirtz/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/hansottowirtz">@
hansottowirtz</a>)</li>
<li>Add <code>useOptimistic()</code> hook to display mutated state
optimistically during an async mutation (<a
href="https://redirect.github.com/facebook/react/pull/26740"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/26740/hovercard">#26740</a>, <a
href="https://redirect.github.com/facebook/react/pull/26772"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/26772/hovercard">#26772</a>, <a
href="https://redirect.github.com/facebook/react/pull/27277"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/27277/hovercard">#27277</a>, <a
href="https://redirect.github.com/facebook/react/pull/27453"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/27453/hovercard">#27453</a>, <a
href="https://redirect.github.com/facebook/react/pull/27454"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/27454/hovercard">#27454</a>, <a
href="https://redirect.github.com/facebook/react/pull/27936"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/27936/hovercard">#27936</a> by
<a class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/acdlite/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/acdlite">@ acdlite</a>)</li>
<li>Added an <code>initialValue</code> argument to
<code>useDeferredValue()</code> hook (<a
href="https://redirect.github.com/facebook/react/pull/27500"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/27500/hovercard">#27500</a>, <a
href="https://redirect.github.com/facebook/react/pull/27509"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/27509/hovercard">#27509</a>, <a
href="https://redirect.github.com/facebook/react/pull/27512"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/27512/hovercard">#27512</a>, <a
href="https://redirect.github.com/facebook/react/pull/27888"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/27888/hovercard">#27888</a>, <a
href="https://redirect.github.com/facebook/react/pull/27550"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/27550/hovercard">#27550</a> by
<a class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/acdlite/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/acdlite">@ acdlite</a>)</li>
<li>Support refs as props, warn on <code>element.ref</code> access (<a
href="https://redirect.github.com/facebook/react/pull/28348"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/28348/hovercard">#28348</a>, <a
href="https://redirect.github.com/facebook/react/pull/28464"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/28464/hovercard">#28464</a>, <a
href="https://redirect.github.com/facebook/react/pull/28731"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/28731/hovercard">#28731</a> by
<a class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/acdlite/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/acdlite">@ acdlite</a>)</li>
<li>Support Custom Elements (<a
href="https://redirect.github.com/facebook/react/pull/22184"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/22184/hovercard">#22184</a>, <a
href="https://redirect.github.com/facebook/react/pull/26524"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/26524/hovercard">#26524</a>, <a
href="https://redirect.github.com/facebook/react/pull/26523"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/26523/hovercard">#26523</a>, <a
href="https://redirect.github.com/facebook/react/pull/27511"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/27511/hovercard">#27511</a>, <a
href="https://redirect.github.com/facebook/react/pull/24541"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/24541/hovercard">#24541</a> by
<a class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/josepharhar/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/josepharhar">@ josepharhar</a>, <a
class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/sebmarkbage/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/sebmarkbage">@ sebmarkbage</a>, <a
class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/gnoff/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/gnoff">@ gnoff</a> and <a
class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/eps1lon/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/eps1lon">@ eps1lon</a>)</li>
<li>Add ref cleanup function (<a
href="https://redirect.github.com/facebook/react/pull/25686"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/25686/hovercard">#25686</a>, <a
href="https://redirect.github.com/facebook/react/pull/28883"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/28883/hovercard">#28883</a>, <a
href="https://redirect.github.com/facebook/react/pull/28910"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/28910/hovercard">#28910</a> by
<a class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/sammy-SC/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/sammy-SC">@ sammy-SC</a>), <a
class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/jackpope/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/jackpope">@ jackpope</a>, and <a
class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/kassens/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/kassens">@ kassens</a>)</li>
<li>Sibling pre-rendering replaced by sibling pre-warming (<a
href="https://redirect.github.com/facebook/react/pull/26380"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/26380/hovercard">#26380</a>, <a
href="https://redirect.github.com/facebook/react/pull/26549"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/26549/hovercard">#26549</a>, <a
href="https://redirect.github.com/facebook/react/pull/30761"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/30761/hovercard">#30761</a>, <a
href="https://redirect.github.com/facebook/react/pull/30800"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/30800/hovercard">#30800</a>, <a
href="https://redirect.github.com/facebook/react/pull/30762"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/30762/hovercard">#30762</a>, <a
href="https://redirect.github.com/facebook/react/pull/30879"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/30879/hovercard">#30879</a>, <a
href="https://redirect.github.com/facebook/react/pull/30934"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/30934/hovercard">#30934</a>, <a
href="https://redirect.github.com/facebook/react/pull/30952"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/30952/hovercard">#30952</a>, <a
href="https://redirect.github.com/facebook/react/pull/31056"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/31056/hovercard">#31056</a>, <a
href="https://redirect.github.com/facebook/react/pull/31452"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/31452/hovercard">#31452</a> by
<a class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/sammy-SC/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/sammy-SC">@ sammy-SC</a>), <a
class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/acdlite/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/acdlite">@ acdlite</a>, <a
class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/gnoff/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/gnoff">@ gnoff</a>, <a
class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/jackpope/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/jackpope">@ jackpope</a>, <a
class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/rickhanlonii/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/rickhanlonii">@ rickhanlonii</a>)</li>
<li>Don’t rethrow errors at the root (<a
href="https://redirect.github.com/facebook/react/pull/28627"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/28627/hovercard">#28627</a>, <a
href="https://redirect.github.com/facebook/react/pull/28641"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/28641/hovercard">#28641</a> by
<a class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/sebmarkbage/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/sebmarkbage">@ sebmarkbage</a>)</li>
<li>Batch sync discrete, continuous, and default lanes (<a
href="https://redirect.github.com/facebook/react/pull/25700"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/25700/hovercard">#25700</a> by
<a class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/tyao1/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/tyao1">@ tyao1</a>)</li>
<li>Switch <code>&lt;Context&gt;</code> to mean
<code>&lt;Context.Provider&gt;</code> (<a
href="https://redirect.github.com/facebook/react/pull/28226"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/28226/hovercard">#28226</a> by
<a class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/gaearon/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/gaearon">@ gaearon</a>)</li>
<li>Changes to <em>StrictMode</em>
<ul>
<li>Handle <code>info</code>, <code>group</code>, and
<code>groupCollapsed</code> in <em>StrictMode</em> logging (<a
href="https://redirect.github.com/facebook/react/pull/25172"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/25172/hovercard">#25172</a> by
<a class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/timneutkens/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/timneutkens">@ timneutkens</a>)</li>
<li>Refs are now attached/detached/attached in <em>StrictMode</em> (<a
href="https://redirect.github.com/facebook/react/pull/25049"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/25049/hovercard">#25049</a> by
<a class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/sammy-SC/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/sammy-SC">@ sammy-SC</a>)</li>
<li>Fix <code>useSyncExternalStore()</code> hydration in
<em>StrictMode</em> (<a
href="https://redirect.github.com/facebook/react/pull/26791"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/26791/hovercard">#26791</a> by
<a class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/sophiebits/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/sophiebits">@ sophiebits</a>)</li>
<li>Always trigger <code>componentWillUnmount()</code> in
<em>StrictMode</em> (<a
href="https://redirect.github.com/facebook/react/pull/26842"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/26842/hovercard">#26842</a> by
<a class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/tyao1/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/tyao1">@ tyao1</a>)</li>
<li>Restore double invoking <code>useState()</code> and
<code>useReducer()</code> initializer functions in <em>StrictMode</em>
(<a href="https://redirect.github.com/facebook/react/pull/28248"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/28248/hovercard">#28248</a> by
<a class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/eps1lon/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/eps1lon">@ eps1lon</a>)</li>
<li>Reuse memoized result from first pass (<a
href="https://redirect.github.com/facebook/react/pull/25583"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/25583/hovercard">#25583</a> by
<a class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/acdlite/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/acdlite">@ acdlite</a>)</li>
<li>Fix <code>useId()</code> in <em>StrictMode</em> (<a
href="https://redirect.github.com/facebook/react/pull/25713"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/25713/hovercard">#25713</a> by
<a class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/gnoff/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/gnoff">@ gnoff</a>)</li>
<li>Add component name to <em>StrictMode</em> error messages (<a
href="https://redirect.github.com/facebook/react/pull/25718"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/25718/hovercard">#25718</a> by
<a class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/sammy-SC/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/sammy-SC">@ sammy-SC</a>)</li>
</ul>
</li>
<li>Add support for rendering BigInt (<a
href="https://redirect.github.com/facebook/react/pull/24580"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/24580/hovercard">#24580</a> by
<a class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/eps1lon/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/eps1lon">@ eps1lon</a>)</li>
<li><code>act()</code> no longer checks <code>shouldYield</code> which
can be inaccurate in test environments (<a
href="https://redirect.github.com/facebook/react/pull/26317"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/26317/hovercard">#26317</a> by
<a class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/acdlite/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/acdlite">@ acdlite</a>)</li>
<li>Warn when keys are spread with props (<a
href="https://redirect.github.com/facebook/react/pull/25697"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/25697/hovercard">#25697</a>, <a
href="https://redirect.github.com/facebook/react/pull/26080"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/26080/hovercard">#26080</a> by
<a class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/sebmarkbage/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/sebmarkbage">@ sebmarkbage</a> and <a
class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/kassens/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/kassens">@ kassens</a>)</li>
<li>Generate sourcemaps for production build artifacts (<a
href="https://redirect.github.com/facebook/react/pull/26446"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/26446/hovercard">#26446</a> by
<a class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/markerikson/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/markerikson">@ markerikson</a>)</li>
<li>Improve stack diffing algorithm (<a
href="https://redirect.github.com/facebook/react/pull/27132"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/27132/hovercard">#27132</a> by
<a class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/KarimP/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/KarimP">@ KarimP</a>)</li>
<li>Suspense throttling lowered from 500ms to 300ms (<a
href="https://redirect.github.com/facebook/react/pull/26803"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/26803/hovercard">#26803</a> by
<a class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/acdlite/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/acdlite">@ acdlite</a>)</li>
<li>Lazily propagate context changes (<a
href="https://redirect.github.com/facebook/react/pull/20890"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/20890/hovercard">#20890</a> by
<a class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/acdlite/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/acdlite">@ acdlite</a> and <a
class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/gnoff/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/gnoff">@ gnoff</a>)</li>
<li>Immediately rerender pinged fiber (<a
href="https://redirect.github.com/facebook/react/pull/25074"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/25074/hovercard">#25074</a> by
<a class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/acdlite/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/acdlite">@ acdlite</a>)</li>
<li>Move update scheduling to microtask (<a
href="https://redirect.github.com/facebook/react/pull/26512"
data-hovercard-type="pull_request"
data-hovercard-url="/facebook/react/pull/26512/hovercard">#26512</a> by
<a class="user-mention notranslate" data-hovercard-type="user"
data-hovercard-url="/users/acdlite/hovercard"
data-octo-click="hovercard-link-click"
data-octo-dimensions="link_type:self"
href="https://redirect.github.com/acdlite">@ acdlite</a>)</li>
<li>Consistently apply throttled retries (<a
href="https://redirect.github.com/facebook/…
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants