Skip to content

[Compiler]: Detect use of callback refs for layout synchronization #33204

Open
@yuta0801

Description

@yuta0801

What kind of issue is this?

  • React Compiler core (the JS output is incorrect, or your app works incorrectly after optimization)
  • babel-plugin-react-compiler (build issue installing or using the Babel plugin)
  • eslint-plugin-react-compiler (build issue installing or using the eslint plugin)
  • react-compiler-healthcheck (build issue installing or using the healthcheck script)

Link to repro

https://stackblitz.com/edit/react-2u9hf3xf?file=src%2FApp.tsx,src%2FClippedText.tsx&terminal=dev

Repro steps

There are two tabs, and each panel contains the same <ClippedText> component. This component measures the content height and conditionally renders a "Read more" button if the content overflows.

Steps to reproduce:

  1. At Tab 1, click the "Read more" button, and confirm that it expands as expected.

  2. Switch to Tab 2 and observe that the "Read more" button does not appear, even if the content overflows.

The issue originates from tab switching being implemented using display: none, which prevents the ref callback in <ClippedText> from accessing layout information when the component is hidden. As a result, the content height cannot be measured correctly.

Notably, this behavior can be reproduced without the React Compiler by manually wrapping <ClippedText> in memo(). When using the React Compiler, disabling memoization requires adding "use no memo" in all relevant components.

While this may not strictly be considered a React Compiler bug, it highlights a class of issues where components rely on rerenders to synchronize layout-dependent side effects --- a pattern that is difficult to detect through conventional rules such as the Rules of Hooks. In such cases, automatic memoization introduced by the compiler can lead to subtle and hard-to-diagnose behavior changes.

For use cases involving visibility toggled via display: none, using <Activity> is likely a more reliable approach, as it is designed to manage component lifecycle transitions more accurately.

This issue was opened at the request of @josephsavona.

How often does this bug happen?

Every time

What version of React are you using?

19.1.0

What version of React Compiler are you using?

19.1.0-rc.1

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions