Skip to content

[devtools]: Prevent false positive render detection in profiler (#33423, #19732) #33964

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

developerjhp
Copy link

@developerjhp developerjhp commented Jul 22, 2025

Summary

Fixes a bug in React DevTools where the profiler incorrectly reported sibling components as re-rendered when they were nested under HostComponents (like <div>) that get filtered out by DevTools. This affected profiler data collection, render highlighting, and inspector cache management.

Background

React DevTools filters out DOM elements (HostComponents) by default to focus on user components. However, this filtering created a blind spot where sibling components under the same HostComponent parent would be incorrectly reported as re-rendered even when their Fiber objects remained identical.
This is a follow-up to #33434

Previous Attempt & Learning

#33434 helped identify that the issue wasn't with didFiberRender logic itself, but with when it was being called. The filtering behavior provided the key insight that components with identical Fiber objects shouldn't trigger render
detection when their parent HostComponents are filtered.

Example scenario:

const Count = () => {
  const [count, setCount] = useState(0);
  console.log('Count Component Rerendered');
  return (
      <button onClick={() => setCount(c => c + 1)}>
          Count: {count}
      </button>
  );
};

const Greeting = () => {
  console.log('Greeting Component Rerendered');
  return <span>Hello World!</span>;
};

const App = () => {
  const [appState, setAppState] = useState(0);
  console.log('App Component Rerendered');
  
  return (
      <main>
          <div>App State: {appState}</div>
          <button onClick={() => setAppState(s => s + 1)}>
              App Rerender Trigger (All children rerender)
          </button>
          <hr />
          <Count />
          <div>
              <Greeting />
          </div>
      </main>
  );
};

Root Cause

The issue occurred because didFiberRender was being called for components whose Fiber objects remained referentially identical (prevFiber === nextFiber) but were nested under HostComponents. When the parent HostComponent processed its children during reconciliation, DevTools would check all child components without recognizing that some hadn't actually re-rendered.

Key insight

If prevFiber === nextFiber and the parent is a filtered HostComponent, then didFiberRender shouldn't be called at all - not because the function is wrong, but because the component genuinely hasn't re-rendered.

Solution

Instead of modifying didFiberRender logic, this fix prevents the function from being called when we can objectively determine a component hasn't re-rendered. The fix adds conditional checks in three critical locations:

  1. Profiler Data Collection (renderer.js:2816)
  • Prevents false positive entries in profiler commit data when components haven't actually re-rendered.
  1. Render Highlighting (renderer.js:3327)
  • Prevents incorrect highlighting of components during trace updates when they haven't changed.
  1. Inspector Cache Management (renderer.js:3359)
  • Preserves cached inspection data when components haven't actually re-rendered, avoiding unnecessary re-computation.

Implementation Details

The fix uses objective criteria to detect when didFiberRender shouldn't be called:

  if (
    prevFiber === nextFiber &&  // Same Fiber object reference
    nextFiber.return != null &&
    (nextFiber.return.tag === HostComponent || nextFiber.return.tag === HostSingleton)  // Parent is filtered HostComponent
  ) {
    // Don't call didFiberRender - component hasn't actually re-rendered
  }

This approach:

  • Addresses false positives at the source
  • Maintains existing didFiberRender logic unchanged
  • Applies consistently across all DevTools features
  • Uses objective, verifiable criteria
  • No performance impact on normal rendering

Related Issues

Fixes #33423, #19732

…book#33423)

  - This commit addresses a bug in React DevTools where the profiler incorrectly reported user components as having re-rendered with the message "The parent component rendered," e
    ven when they had not. This typically occurred for sibling components (like  in the reported issue) nested under a  (e.g., ) when the parent re-rendered.

  - Problem: The  function, which determines if a component has rendered, was being called for components whose Fiber object remained referentially identical (). While  correctly
    checks for changes in , , and , the issue stemmed from the fact that it was invoked at all for these unchanged components, leading to misleading "render" indications in the profiler a
    nd highlight updates. The core problem was not the logic "within" , but rather the conditions under which it was "called".

  - Solution: To resolve this, a conditional check has been added within the  function, which is responsible for traversing and updating the Fiber tree. Before calling  for user components (Function, Class, Memo, ForwardRef components), the system now verifies two key conditions:
    1.  : The Fiber object itself has not changed (i.e., it's the same instance).
    2.   is a  or : The component's direct parent is a host element (like a ).
    If both conditions are met, it indicates that the component has not genuinely re-rendered, and  is explicitly set to . This prevents  from being called unnecessarily and avoids the false positive reporting in the DevTools profiler and render highlighting. The same logic is applied when checking if  has updated, ensuring consistency.

  - This change significantly improves the accuracy of the React DevTools profiler and render highlighting, providing developers with more reliable information about component re-renders and bailouts.

Fixes facebook#33423
Relates to facebook#33434
@developerjhp developerjhp changed the title [devtools]: Prevent false positive render detection in profiler (#33423) [devtools]: Prevent false positive render detection in profiler (#33423, #19732) Jul 23, 2025
…er filtered HostComponents

  This commit addresses a bug in React DevTools where sibling user components were incorrectly reported as having re-rendered when they were nested under HostComponents (like <div>) that get filtered out by the DevTools component tree.

  ## Problem
  When a user component (e.g., Count) triggers a re-render within a HostComponent
  container, DevTools would incorrectly report sibling components (e.g., Greeting) as having re-rendered, even when their Fiber objects remained referentially
  identical (prevFiber === nextFiber). This created misleading information in:
    - Profiler data collection (false entries in commit data)
    - Render highlighting (incorrect visual indicators)
    - Inspector cache management (unnecessary invalidation)

  ## Root Cause
  The issue occurred because didFiberRender() was being called for components
  whose Fiber objects hadn't actually changed, but were children of HostComponents
  that were being processed during reconciliation. Since HostComponents are
  filtered out by default in DevTools, the relationship between unchanged sibling
  components wasn't being properly recognized.                                                                                                                                                                                                                                                     │

  ## Solution
  Instead of modifying the didFiberRender() function itself, this fix prevents
  the function from being called when we can determine that a component hasn't
  actually re-rendered. The key insight is that if:
    - prevFiber === nextFiber (same Fiber object reference)
    - nextFiber.return is a HostComponent or HostSingleton
  Then the component didn't actually re-render and didFiberRender() shouldn't be invoked.
@developerjhp
Copy link
Author

@hoxyq

I've implemented a fix for the false positive render detection issue we discussed in #33423.

The solution prevents calling didFiberRender when prevFiber === nextFiber and the parent is a HostComponent/HostSingleton, which addresses the filtering issue you mentioned. I've added conditional checks in three locations:

  1. Profiler data collection
  2. Render highlighting
  3. Inspector cache management

I've tested this manually with the Chrome extension and confirmed it fixes both the profiler data and highlighting issues. Would you mind taking a look when you have a chance?

Thanks for the guidance on the root cause - it really helped narrow down the solution! 🙏

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.

Bug: profiler incorrectly reports 'The parent component rendered'
2 participants