Skip to content

Conversation

@everettbu
Copy link

Mirror of facebook/react#35502
Original author: kanikaa88


Summary

Implements component name search functionality in the Profiler trace view as requested in #32995.

Changes

  • Added search state management to ProfilerContext
  • Created ProfilerSearchInput component (similar to ComponentSearchInput)
  • Integrated search input into Profiler toolbar
  • Search only considers components from the selected commit

Features

  • ✅ Cmd+f / Ctrl+f keyboard shortcut (handled by SearchInput component)
  • ✅ Text and regex search support (e.g., /^Button/)
  • ✅ Result count display (e.g., "1 | 5")
  • ✅ Navigation between matches (Enter/Shift+Enter or arrow buttons)
  • ✅ Auto-selects first matching result
  • ✅ Clears when commit changes
  • ✅ Only searches the selected commit (not the whole trace)
  • ✅ Works in both Flamegraph and Ranked views

Implementation Details

  • Follows the same pattern as Components panel search
  • Search input appears conditionally when:
    • Legacy profiler tabs (flame-chart/ranked-chart) are selected
    • Commits are recorded
    • A commit is selected
  • Search filters components recursively through the commit tree
  • Uses existing createRegExp utility for pattern matching

Testing

  • ✅ Linting passed
  • ✅ Flow type checking passed (dom-node renderer)
  • ✅ Tested locally in DevTools shell
  • ✅ Follows existing codebase patterns

Fixes #32995

Implements search functionality for components in Profiler trace as requested in #32995.

Features:
- Adds search input that appears when a commit is selected
- Supports text and regex search (e.g., /^Button/)
- Shows result count and allows navigation between matches
- Only searches components in the selected commit
- Follows same pattern as Components panel search
- Clears search when commit changes
- Cmd+f / Ctrl+f keyboard shortcut support

The search input appears in the Profiler toolbar between the root selector
and settings button, only when a commit is selected in flame-chart or
ranked-chart views.
@greptile-apps
Copy link

greptile-apps bot commented Jan 13, 2026

Greptile Overview

Greptile Summary

This PR implements component name search functionality for the Profiler's Flamegraph and Ranked views, mirroring the pattern used in the Components panel. The implementation adds search state management to ProfilerContext, creates a new ProfilerSearchInput component, and integrates it into the Profiler toolbar.

Key Implementation Details

Architecture: The search functionality follows the same architectural pattern as ComponentSearchInput, with appropriate adaptations for the Profiler's context-based state management (using direct callbacks instead of a dispatcher pattern). The search operates exclusively on the selected commit's component tree.

Search Behavior: When a user enters a search term, the implementation recursively traverses the commit tree, tests each component's display name against a regex pattern (supporting both text and /regex/ syntax via the existing createRegExp utility), and auto-selects the first matching result. Navigation between results is supported via Enter/Shift+Enter or arrow buttons.

State Management: Search state (text, results, and current index) is properly integrated into ProfilerContext and included in the context value's useMemo dependencies. A separate effect clears the search when the commit changes, which aligns with the stated requirement.

Critical Issue Found

There is a race condition between two useEffect hooks in ProfilerContext.js (lines 331-385):

  1. The search effect (lines 332-378) has selectedCommitIndex in its dependencies
  2. The commit-change clearing effect (lines 381-385) also depends on selectedCommitIndex
  3. When a commit changes, both effects run, but React executes them in definition order
  4. The search effect runs first and sees the OLD searchText with the NEW selectedCommitIndex
  5. This causes a search on the new commit with stale search text, potentially auto-selecting a wrong fiber (line 363)
  6. Then the clearing effect runs and clears the search state, but the fiber selection persists

This results in a fiber being selected that doesn't match any search criteria after commit navigation, creating a confusing UX.

Recommended fix: Change the commit-change effect from useEffect to useLayoutEffect to ensure it runs synchronously before the search effect can execute on subsequent renders.

Overall Assessment

The implementation is well-structured and follows established codebase patterns. The core search logic is sound - proper tree traversal, regex handling, result navigation, and state synchronization. The integration is clean and appropriately conditional. However, the race condition bug needs to be addressed before merging, as it affects the user experience when navigating between commits with an active search.

Confidence Score: 3/5

  • This PR has good architecture but contains a race condition bug that affects UX
  • The implementation follows established patterns and has clean integration, but the race condition between search and commit-change effects will cause incorrect fiber selection when navigating commits with an active search. This is a deterministic logic bug that needs fixing, though it doesn't cause crashes or data corruption.
  • ProfilerContext.js requires attention to fix the race condition between the search effect and commit-change effect

Important Files Changed

File Analysis

Filename Score Overview
packages/react-devtools-shared/src/devtools/views/Profiler/ProfilerSearchInput.js 5/5 New component following ComponentSearchInput pattern, with proper state sync handling when search is cleared externally
packages/react-devtools-shared/src/devtools/views/Profiler/Profiler.js 5/5 Simple integration of ProfilerSearchInput with appropriate conditional rendering
packages/react-devtools-shared/src/devtools/views/Profiler/ProfilerContext.js 3/5 Core search logic implementation with race condition between search effect and commit-change effect causing unintended fiber selection

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

1 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines +331 to +385
// Update search results when search text, commit, or root changes
useEffect(() => {
if (
searchText === '' ||
selectedCommitIndex === null ||
rootID === null ||
!profilingData
) {
setSearchResults([]);
setSearchIndex(null);
return;
}

const commitTree = profilerStore.profilingCache.getCommitTree({
commitIndex: selectedCommitIndex,
rootID,
});

const results = performSearch(searchText, commitTree);
setSearchResults(results);

// Set initial search index
if (results.length > 0) {
// If current selected fiber matches, find its index
if (selectedFiberID !== null && results.includes(selectedFiberID)) {
setSearchIndex(results.indexOf(selectedFiberID));
} else {
setSearchIndex(0);
// Auto-select first result
const firstResultID = results[0];
const node = commitTree.nodes.get(firstResultID);
if (node) {
selectFiber(firstResultID, node.displayName || 'Anonymous');
}
}
} else {
setSearchIndex(null);
}
}, [
searchText,
selectedCommitIndex,
rootID,
profilingData,
profilerStore,
performSearch,
selectedFiberID,
selectFiber,
]);

// Clear search when commit changes
useEffect(() => {
setSearchTextState('');
setSearchResults([]);
setSearchIndex(null);
}, [selectedCommitIndex]);
Copy link

Choose a reason for hiding this comment

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

There's a race condition between the search effect and the commit-change effect. When selectedCommitIndex changes, both effects run, but the search effect runs first (lines 332-378) and sees the OLD searchText value combined with the NEW selectedCommitIndex. This causes:

  1. Search effect performs a search on the new commit using the old search text
  2. First matching result gets auto-selected (line 363)
  3. Then the commit-change effect (lines 381-385) clears the search state
  4. Result: A fiber is selected that doesn't match any search criteria

To fix this, the commit-change effect should use useLayoutEffect instead of useEffect to ensure it runs before the search effect on subsequent renders, or the search effect should check if it's running due to a commit change and skip the auto-selection in that case.

Example fix for the commit-change effect:

Suggested change
// Update search results when search text, commit, or root changes
useEffect(() => {
if (
searchText === '' ||
selectedCommitIndex === null ||
rootID === null ||
!profilingData
) {
setSearchResults([]);
setSearchIndex(null);
return;
}
const commitTree = profilerStore.profilingCache.getCommitTree({
commitIndex: selectedCommitIndex,
rootID,
});
const results = performSearch(searchText, commitTree);
setSearchResults(results);
// Set initial search index
if (results.length > 0) {
// If current selected fiber matches, find its index
if (selectedFiberID !== null && results.includes(selectedFiberID)) {
setSearchIndex(results.indexOf(selectedFiberID));
} else {
setSearchIndex(0);
// Auto-select first result
const firstResultID = results[0];
const node = commitTree.nodes.get(firstResultID);
if (node) {
selectFiber(firstResultID, node.displayName || 'Anonymous');
}
}
} else {
setSearchIndex(null);
}
}, [
searchText,
selectedCommitIndex,
rootID,
profilingData,
profilerStore,
performSearch,
selectedFiberID,
selectFiber,
]);
// Clear search when commit changes
useEffect(() => {
setSearchTextState('');
setSearchResults([]);
setSearchIndex(null);
}, [selectedCommitIndex]);
// Clear search when commit changes
useLayoutEffect(() => {
setSearchTextState('');
setSearchResults([]);
setSearchIndex(null);
}, [selectedCommitIndex]);
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/react-devtools-shared/src/devtools/views/Profiler/ProfilerContext.js
Line: 331:385

Comment:
There's a race condition between the search effect and the commit-change effect. When `selectedCommitIndex` changes, both effects run, but the search effect runs first (lines 332-378) and sees the OLD `searchText` value combined with the NEW `selectedCommitIndex`. This causes:

1. Search effect performs a search on the new commit using the old search text
2. First matching result gets auto-selected (line 363)
3. Then the commit-change effect (lines 381-385) clears the search state
4. Result: A fiber is selected that doesn't match any search criteria

To fix this, the commit-change effect should use `useLayoutEffect` instead of `useEffect` to ensure it runs before the search effect on subsequent renders, or the search effect should check if it's running due to a commit change and skip the auto-selection in that case.

Example fix for the commit-change effect:

```suggestion
  // Clear search when commit changes
  useLayoutEffect(() => {
    setSearchTextState('');
    setSearchResults([]);
    setSearchIndex(null);
  }, [selectedCommitIndex]);
```

How can I resolve this? If you propose a fix, please make it concise.

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.

3 participants