react changelog


Here's the latest scoop on the updates and improvements made to the React codebase! πŸš€

  • New feature: Batch Suspense Boundary Reveal with Throttle πŸŽ‰ This update brings a much-needed feature to server-side rendering (SSR) streaming by implementing throttled reveals for Suspense boundaries. This ensures smoother transitions and prevents flashing reveals, especially noticeable on dynamic sites. The changes enhance the Fizz runtime by batching reveals into single paint operations, improving performance and paving the way for future SSR View Transitions.

  • New feature: Emit link rel="expect" to block render before the shell has fully loaded πŸš€ React now uses a <link rel="expect"> tag to control rendering behavior in SSR applications, ensuring that content outside Suspense boundaries doesn't display until fully unsuspended. This prevents content "popping" and leverages the new Chromium API for view transitions, improving rendering control, particularly in multi-page applications.

  • Improvement: Restore all Transitions for Tree updates 🌳 React DevTools gets a boost with reintroduced transition animations for tree updates, thanks to a new hook, useChangeOwnerAction. This enhancement ensures smoother user interactions and maintains transition continuity during tree updates, offering a more responsive and visually appealing experience.

  • New feature: Add Fragment Refs to Fabric with intersection observer support 🧩 React Native (RN) now supports Fragment Refs through the Fabric configuration, enhancing how fragments interact with intersection observers. This feature, validated in the Catalyst app, adds dynamic UI behaviors and includes a test suite to ensure functionality.

  • New feature: Initial experiment for adding a performance tool πŸš€ Introducing a performance measurement tool for React code! This experimental feature, review-react-runtime, helps evaluate runtime performance by collecting metrics like render time and web vitals. It’s a step towards better understanding and optimizing React code performance.

  • Bugfix: Patch for reactive refs in inferred effect dependencies πŸ› A fix for the React compiler that ensures stable-typed value blocks are correctly inferred as reactive. This patch enhances the accuracy of dependency inference, particularly in complex scenarios involving conditional logic.

  • Improvement: Outline if a boundary would add too many bytes to the next completion πŸ“ Enhancements to the Fizz server heuristic prevent excessive inlining of small boundaries, improving document streaming capabilities. This update introduces a size limit to ensure content is worth outlining, addressing potential rendering order issues.

  • Bugfix: Reset Instructions on ResumableState πŸ”„ This fix addresses incomplete state handling in the React shell by resetting the ResumableState, ensuring it reflects the current status of the flushing process and maintains accurate instruction state.

  • Bugfix: Expand StoreContext to const / let / function variants πŸ› οΈ A bugfix in the React compiler improves the handling of hoisted context variables, preventing duplicate declarations and preserving variable type information. Extensive testing ensures the correctness of the compiler's behavior in various scenarios.

These updates bring exciting improvements and fixes, enhancing performance, user experience, and developer tools in the React ecosystem! πŸŽ‰

Included Commits

2025-05-01T20:09:37 See commit

The commit titled "Batch Suspense Boundary Reveal with Throttle" addresses a previously unimplemented feature in React's server-side rendering (SSR) streaming, specifically regarding the throttling of Suspense boundaries. While client navigations benefited from a 300ms throttle to prevent flashing reveals during rapid updates, this functionality was lacking in SSR, leading to a disjointed user experience on dynamic sites. The update modifies the Fizz runtime to enable throttled reveals, ensuring that layout and paint work is batched together for smoother visual transitions during page loads and reloads.

To implement this, the commit introduces a mechanism that tracks the last paint after a complete operation and queues subsequent operations to flush them as a single batch. This adjustment not only enhances the performance of Suspense boundaries but also lays the groundwork for future support of View Transitions in SSR, which require batching to ensure cohesive animations. The changes span multiple files within the React codebase, including modifications to various components and tests to ensure the new functionality is properly integrated and functioning as intended.

Files changed

  • packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js
  • packages/react-dom-bindings/src/server/fizz-instruction-set/ReactDOMFizzInlineCompleteBoundary.js
  • packages/react-dom-bindings/src/server/fizz-instruction-set/ReactDOMFizzInlineShellTime.js
  • packages/react-dom-bindings/src/server/fizz-instruction-set/ReactDOMFizzInstructionSetExternalRuntime.js
  • packages/react-dom-bindings/src/server/fizz-instruction-set/ReactDOMFizzInstructionSetInlineCodeStrings.js
  • packages/react-dom-bindings/src/server/fizz-instruction-set/ReactDOMFizzInstructionSetShared.js
  • packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
  • packages/react-dom/src/__tests__/ReactDOMFizzStaticBrowser-test.js
  • packages/react-dom/src/__tests__/ReactDOMFloat-test.js
  • packages/react-markup/src/ReactFizzConfigMarkup.js
  • packages/react-noop-renderer/src/ReactNoopServer.js
  • packages/react-server/src/ReactFizzServer.js
  • scripts/rollup/generate-inline-fizz-runtime.js
2025-04-25T15:52:28 See commit

This commit introduces a new feature in React that emits a <link rel="expect"> tag to control rendering behavior in server-side rendered (SSR) applications. The goal is to ensure that content outside of Suspense boundaries does not display until it has fully unsuspended, thereby avoiding the unpredictable content "popping" that can occur with traditional document streaming. By utilizing the new Chromium API for view transitions, the commit allows React to manage when to paint content more effectively, particularly in multi-page applications (MPAs). This ensures that the initial shell of the document waits for the necessary resources to be fully streamed before rendering.

The implementation details specify that the rel="expect" tag will reference a bootstrap script or an empty template if no script is available, marking the point at which rendering should be blocked. The commit also addresses potential issues with large documents by suggesting that large Suspense boundaries should be outlined outside the shell, even if they are available immediately. This change applies specifically to full document renders, as partial renders do not provide enough information to guarantee the streaming parts. Overall, this commit enhances the control of rendering in React applications, improving user experience by reducing the likelihood of content thrashing during load times.

Files changed

  • fixtures/ssr/server/render.js
  • fixtures/ssr/src/components/Chrome.js
  • packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js
  • packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
  • packages/react-dom/src/__tests__/ReactDOMFizzServerBrowser-test.js
  • packages/react-dom/src/__tests__/ReactDOMFizzServerEdge-test.js
  • packages/react-dom/src/__tests__/ReactDOMFizzServerNode-test.js
  • packages/react-dom/src/__tests__/ReactDOMFizzStatic-test.js
  • packages/react-dom/src/__tests__/ReactDOMFizzStaticBrowser-test.js
  • packages/react-dom/src/__tests__/ReactDOMFizzStaticNode-test.js
  • packages/react-dom/src/__tests__/ReactDOMFloat-test.js
  • packages/react-dom/src/__tests__/ReactDOMLegacyFloat-test.js
  • packages/react-dom/src/__tests__/ReactDOMSingletonComponents-test.js
  • packages/react-dom/src/__tests__/ReactRenderDocument-test.js
  • packages/react-dom/src/test-utils/FizzTestUtils.js
  • packages/react-markup/src/ReactFizzConfigMarkup.js
  • packages/react-server-dom-fb/src/__tests__/ReactDOMServerFB-test.internal.js
  • packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js
  • packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js
  • packages/react-server/src/ReactFizzServer.js
2025-04-25T19:42:40 See commit

This commit addresses an issue in the React compiler related to the inference of reactive references in effect dependencies and inlined JSX, particularly when using stable-typed value blocks. The problem arose after the introduction of type inference for phi nodes, which incorrectly classified certain stable-typed expressions, like those using conditional operators, as non-reactive. To rectify this, the commit modifies the InferReactivePlaces functionality to ensure that stability is correctly propagated without introducing a new pass, thereby enhancing the accuracy of dependency inference in experimental features.

The changes include the addition of new functions and a StableSidemap class that tracks and manages the stability of identifiers throughout the compilation process. This class evaluates instructions to determine whether they originate from stable sources, such as known hook calls, and appropriately marks identifiers as stable or non-stable. Furthermore, the commit introduces tests to validate the new behavior, ensuring that the inference logic correctly handles scenarios where stable values are derived from conditional expressions. Overall, this patch aims to improve the reliability of React's effect dependency inference mechanism, particularly in complex scenarios involving conditional logic.

Files changed

  • compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts
  • compiler/packages/babel-plugin-react-compiler/src/Inference/InferReactivePlaces.ts
  • compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/reactive-ref-ternary.expect.md
  • compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/reactive-ref-ternary.js
  • compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.expect.md
2025-04-28T19:50:06 See commit

The commit titled "Reset Instructions on ResumableState" addresses an issue with the handling of incomplete states in the React shell. When an incomplete state is created, it results in nothing being flushed, which necessitates a reset of the ResumableState. While some elements, like preloads in headers, remain relevant, others need to be cleared since they rely on the assumption that a flush has occurred. Specifically, the instructions state was not reset, which is problematic because no instructions were actually flushed.

The changes made in the commit involve modifying the resetResumableState function within the ReactFizzConfigDOM.js file. An additional line of code was added to reset the instructions property of the ResumableState to NothingSent, indicating that no instructions could have been flushed due to the incomplete state. This adjustment ensures that the ResumableState accurately reflects the current status of the flushing process.

Files changed

  • packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js
2025-04-29T23:13:28 See commit

This commit enhances the heuristic for determining whether to outline a boundary in the React Fizz server, specifically focusing on the accumulation of the size of currently written boundaries. By starting from the root size (minus the preamble), the update aims to prevent excessive inlining of small boundaries, allowing for better document streaming capabilities when using Suspense boundaries, such as wrapping each paragraph in a document. The commit introduces a size limit of at least 500 bytes for content to be considered worth outlining, addressing concerns about potentially useless nested Suspense boundaries that could lead to disordered rendering.

Additionally, the changes made in this commit highlight the trade-offs involved in outlining boundaries, particularly when dealing with smaller content sizes. If the content is too small, such as in the case of numerous short paragraphs, they may not be outlined, resulting in some appearing out of order. Although this can be mitigated by using SuspenseList, it remains an unfortunate effect of the new heuristic. Overall, the commit modifies several files to implement these changes, while also noting that the default behavior is unlikely to outline content within the viewport.

Files changed

  • fixtures/ssr/server/render.js
  • fixtures/ssr/src/components/Chrome.js
  • fixtures/ssr/src/components/LargeContent.js
  • packages/react-server/src/ReactFizzServer.js
2025-04-30T14:47:18 See commit

This commit introduces Fragment Reference (Refs) support to React Native (RN) via the Fabric configuration, specifically implementing the observeUsing and unobserveUsing methods. The implementation is largely derived from the existing DOM functionality, with the intention to potentially share code in the future, though it remains separate for now. The commit also includes a basic test for the Fabric integration, acknowledging that testing specific methods requires extensive mocking, which may not yield significant value at this stage. The author has validated the implementation by building Fabric and testing it within the Catalyst app, confirming that intersection observers work end-to-end.

In terms of code changes, the commit modifies several files, adding new functionalities for managing observers in the Fragment instances, and adjusting related types and functions. It also adds a new test suite specifically for Fragment Refs in Fabric, which includes tests for attaching refs to fragments and handling ref callbacks. Additionally, the commit updates feature flags to enable Fragment Refs, ensuring that this new capability can be toggled as needed. Overall, this change enhances the React Native framework by improving how fragments can interact with intersection observers, paving the way for more dynamic UI behaviors.

Files changed

  • packages/react-native-renderer/src/ReactFiberConfigFabric.js
  • packages/react-native-renderer/src/__tests__/ReactFabricFragmentRefs-test.internal.js
  • packages/react-reconciler/src/ReactFiberTreeReflection.js
  • packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js
  • packages/shared/forks/ReactFeatureFlags.native-fb.js
  • scripts/error-codes/codes.json
2025-04-30T17:51:40 See commit

The commit titled "Restore all Transitions for Tree updates" focuses on enhancing the React DevTools by reintroducing transition animations for tree updates. This is achieved through modifications in several components, particularly by implementing a new hook called useChangeOwnerAction. This hook streamlines the process of selecting an owner for an element within the component tree, replacing the previous method that directly dispatched actions. The changes ensure that user interactions, such as double-clicks and keyboard events, now utilize this new hook, which improves the overall user experience by maintaining the continuity of transitions during tree updates.

In addition to the new hook, the commit also refines the context management for the tree state and dispatcher, which enhances the handling of asynchronous requests related to element ownership. By integrating these updates across various components, the commit not only restores the desired transition effects but also optimizes the underlying architecture for better performance and maintainability. Overall, these changes contribute to a more responsive and visually appealing interface for users interacting with the React DevTools.

Files changed

  • packages/react-devtools-shared/src/devtools/views/Components/Element.js
  • packages/react-devtools-shared/src/devtools/views/Components/OwnersListContext.js
  • packages/react-devtools-shared/src/devtools/views/Components/OwnersStack.js
  • packages/react-devtools-shared/src/devtools/views/Components/Tree.js
  • packages/react-devtools-shared/src/devtools/views/Components/TreeContext.js
2025-04-30T19:44:05 See commit

This commit introduces an experimental performance measurement tool for React code within the agent framework, aimed at providing insights into the performance of React applications. The new tool, named review-react-runtime, allows users to evaluate the runtime performance of their React components by collecting various metrics, including render time and web vitals such as Cumulative Layout Shift (CLS) and Largest Contentful Paint (LCP). The implementation leverages Puppeteer for browser automation to run the React code and gather performance data, which is then formatted and returned to the user.

The commit includes significant updates to several files, notably introducing a new utility for measuring performance, runtimePerf.ts, which handles the parsing and transpilation of React code using Babel, as well as the rendering and performance measurement logic in a browser environment. Additionally, it modifies the package configuration to include necessary dependencies for testing and performance analysis. This initial experiment aims to facilitate better understanding and optimization of React code performance, ultimately leading to improved application responsiveness and user experience.

Files changed

  • compiler/packages/react-mcp-server/package.json
  • compiler/packages/react-mcp-server/src/index.ts
  • compiler/packages/react-mcp-server/src/utils/runtimePerf.ts
  • compiler/yarn.lock
2025-04-30T21:18:58 See commit

This commit addresses a bug in the React compiler related to the handling of hoisted context variables, specifically in the PruneHoistedContexts phase. The previous implementation incorrectly stripped hoisted declarations and inserted duplicate DeclareContext declarations when handling reassigned context variables. The solution involves modifying the handling of StoreContext to retain information about variable types (const, let, etc.) rather than always lowering them to a DeclareContext followed by a StoreContext. This change allows for better preservation of information in High-Level Intermediate Representation (HIR) and simplifies the pruning of hoisted contexts.

The modifications include updates to several files within the compiler, and extensive testing was performed to ensure that the changes did not introduce new issues. Approximately 0.01% of compiled files were affected, with around 25% of those changes being direct bug fixes. New test fixtures were also added to cover various scenarios involving context variable reassignments and hoisting, ensuring the correctness of the compiler's behavior in these cases.

Files changed

  • compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts
  • compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts
  • compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts
  • compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutableLifetimes.ts
  • compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts
  • compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts
  • compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneHoistedContexts.ts
  • compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-3-iife.expect.md
  • compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-3.expect.md
  • compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-inline-iife-reassign.expect.md
  • compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/context-variable-reassigned-outside-of-lambda.expect.md
  • compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/for-loop-with-context-variable-iterator.expect.md
  • compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/for-loop-with-context-variable-iterator.js
  • compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisted-context-variable-in-outlined-fn.expect.md
  • compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisted-context-variable-in-outlined-fn.js
  • compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-invalid-tdz-let.expect.md
  • compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-let-declaration-without-initialization.expect.md
  • compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-let-declaration-without-initialization.js
  • compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-reassigned-let-declaration.expect.md
  • compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-reassigned-twice-let-declaration.expect.md
  • compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-captures-context-variable.expect.md
  • compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-captures-context-variable.js
  • compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lambda-reassign-shadowed-primitive.expect.md
  • compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-extended-contextvar-scope.expect.md
  • compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-reordering-deplist-controlflow.expect.md
  • compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useMemo-reordering-depslist-controlflow.expect.md
  • compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-context-var-reassign-no-scope.expect.md
  • compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-context-var-reassign-no-scope.js
  • compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-returned-inner-fn-reassigns-context.expect.md
  • compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-effect-cleanup-reassigns.expect.md
  • compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-effect-cleanup-reassigns.js
  • compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-operator-conditional.expect.md