[DevTools] Fix Profiler inaccuracy caused by stale PerformedWork flag on unvisited fibers#35645
[DevTools] Fix Profiler inaccuracy caused by stale PerformedWork flag on unvisited fibers#35645yongsk0066 wants to merge 1 commit intofacebook:mainfrom
Conversation
|
Hey @hoxyq ! The DevTools/Compiler mismatch in profiler has been bugging me. Would appreciate if you could take a look :) |
Hey, thank you for upstreaming this! The issue seems similar to #33423. Could you please confirm if my observations apply to your case as well? If so, then I left some thoughts on potential solution here. We could start by adding a test that fails with a current implementation and then triage the reconciliation logic in DevTools. |
Yeah, I think this is the same issue. My case is triggered by the Compiler's caching, but it's essentially a bailout case too - both end up with identical fiber references that shouldn't be marked as rendered. I retested the #33423 repro with the latest DevTools, and the issue still occurs even with the DOM filter disabled. So I don't think filtering is the root cause here. 2026-02-03.1.22.00.movWith my fix applied, both cases work correctly: 2026-02-03.1.27.07.movThe actual root cause seems to be: when a parent bails out, children aren't visited, so createWorkInProgress never gets called and the flags stay stale. So checking fiber identity makes sense here - if |
Something is wrong here, these seems to be identical issues. If I make this change in the test you've provided: t0 = (
- <div>
- <Child count={count} />
- </div>
+ <Child count={count} />
);the test passes. |
You're right, sorry about the confusion. the DOM filter wasn't properly applied when I tested (seems like it doesn't take effect immediately after refresh). As I understand it, DOM filter is just for visual preference in DevTools. whether to show/hide DOM elements in the tree. It shouldn't affect how we determine if a component actually rendered or not, right? So the real issue is that DOM filter ON vs OFF produces different results for render detection, when it should be consistent. Preventing the child traversal for filtered fibers could be an option, but looking at this comment #L5520-L5521,
it seems like the traversal is needed to manage their placement in DevTools tree. So I think handling it in The test I added fails on main and passes with my fix. Let me know if you'd like me to adjust anything. :) |
Summary
Fixes an issue where DevTools Profiler reports components as "rendered" and "Highlight updates" flashes on components that were actually skipped.
This can cause confusion for developers using React Compiler, as cached components appear to be re-rendering in DevTools—making it seem like optimizations aren't working when they actually are.
When React Compiler caches JSX elements, the parent may bail out entirely (
childLanes === 0), and child fibers are never visited by the reconciler. However,didFiberRenderwas checking thePerformedWorkflag which could be stale from a previous render, causing false positives in the Profiler.Here's an example to reproduce the issue (also available in my demo repo). Note that
ChildComponentis wrapped with a<div>.Compiled output (some parts omitted, full output available in playground or demo repo):
I referenced a similar comparison pattern from renderer.js#L4936-L4940 (introduced in #30684), which uses fiber identity to check if a child was not visited. This fix adds the same check before checking the
PerformedWorkflag—if the fiber is the same object, it was never visited this render, so any flag is stale.Note: This is different from the "We don't reflect bailouts" case—that's for components that were visited but bailed out via
shouldComponentUpdateorReact.memo, while this fix handles fibers that were never visited because the parent bailed out entirely withchildLanes === 0.How did you test this change?
Added a test case using
useMemoCacheto simulate React Compiler's JSX caching behavior. The test verifies that cached children are not reported infiberActualDurations.I created a reproduction demo at https://github.com/yongsk0066/devtools-rendered-demo (live demo). Tested with React Developer Tools 7.0.1 (10/20/2025). To reproduce the issue, enable "Highlight updates when components render" and check if highlights appear on cached children, or check in Profiler if cached components are shown without hatching.
I also built the DevTools extension locally with the fix
Before fix:
profiling json
wrapped.mp4
After fix:
profiling json
fixed_wrapped.mp4
cc @hoxyq