-
Notifications
You must be signed in to change notification settings - Fork 46.9k
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
Add Component Highlighting to Profiler DevTools #17934
Conversation
This pull request is automatically built and testable in CodeSandbox. To see build info of the built libraries, click here or the icon next to each commit SHA. Latest deployment of this branch, based on commit ce9b3a8:
|
const highlightNativeElement = useCallback( | ||
(id: number) => { | ||
const element = store.getElementByID(id); | ||
const rendererID = store.getRendererIDForElement(id); | ||
if (element !== null && rendererID !== null) { | ||
bridge.send('highlightNativeElement', { | ||
displayName: element.displayName, | ||
hideAfterTimeout: false, | ||
id, | ||
openNativeElementsPanel: false, | ||
rendererID, | ||
scrollIntoView: false, | ||
}); | ||
} | ||
}, | ||
[store, bridge], | ||
); | ||
|
||
// Highlight last hovered element. | ||
const handleElementMouseEnter = useCallback( | ||
id => { | ||
highlightNativeElement(id); | ||
}, | ||
[highlightNativeElement], | ||
); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This section is also repeated in packages/react-devtools-shared/src/devtools/views/Profiler/CommitRanked.js
and also in
packages/react-devtools-shared/src/devtools/views/Components/Tree.js.
Maybe better to create a separate hook file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the comment, Yeah I absolutely agree, I will try to use a hook for the highlighting functionality:)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, now I extracted the highlighting logic to the hooks file, and created a hook called useNativeElementHighlighter
, this hook exposes two methods:
highlightNativeElement
: method used to highlight an element using its idclearNativeElementHighlight
: method used to clear highlighting of elements
); | ||
|
||
// Highlight last hovered element. | ||
const handleElementMouseEnter = useCallback( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@M-Izadmehr, can you please explain why you wrap in another useCallback
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done:)
I removed the useless useCallback
.
I'm going to hold off doing a review for now since it sounds like there are planned changes. 😄 |
@bvaughn As a response to the reviews I made the following changes:
I guess it is now in a good state to be merged:)) |
Might be worth profiling the profiler (in the test shell) before and after this change to see if we added any extra renders or otherwise did anything that would cause a regression in the flame chart views. I'll review this sometime in the next couple of days though~ |
Any chance you were able to do this? 😁 |
I did a quick test. I don't see any big perf regressions, but I do see a UX problem: Highlights always get stuck. Looks like anytime I'm not moused over the root flamegraph node, its DOM element is highlighted - and mousing out of the graph doesn't clear the highlight either, leaving it stuck on the page. |
Thanks for the comment :)
As a result, I removed that unnecessary logic (ao that logic will be similar to components devtools). |
packages/react-devtools-shared/src/devtools/views/Components/Tree.js
Outdated
Show resolved
Hide resolved
packages/react-devtools-shared/src/devtools/views/Profiler/CommitFlamegraph.js
Show resolved
Hide resolved
@@ -115,9 +122,21 @@ function CommitFlamegraph({chartData, commitTree, height, width}: Props) { | |||
return null; | |||
}, [chartData, selectedFiberID, selectedChartNodeIndex]); | |||
|
|||
// Highlight last hovered element. | |||
const handleElementMouseEnter = id => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unnecessary function wrapper. I'd suggest just passing highlightNativeElement
directly (or if you think the naming is clearer, just alias, e.g. const handleElementMouseEnter = highlightNativeElement
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After merging the other PR, this method now does two actions:
- Adding the highlighting,
- Setting the
fiberData
used for the tooltip,
So, I guess we can keep the wrapper.
|
||
const selectedFiberIndex = useMemo( | ||
() => getNodeIndex(chartData, selectedFiberID), | ||
[chartData, selectedFiberID], | ||
); | ||
|
||
// Highlight last hovered element. | ||
const handleElementMouseEnter = id => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above comment:)
packages/react-devtools-shared/src/devtools/views/Profiler/CommitRanked.js
Show resolved
Hide resolved
Thanks for the comments, |
Sounds good @M-Izadmehr. The other PR has been merged! |
@M-Izadmehr Still planning to update this PR? Or would you like me to finish it up? |
@bvaughn Sorry last week was super busy with some releases, I actually wanted to do it in the weekend, does it sound good?:) |
Sure sounds fine. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While reviewing this, I realized that if you load exported profiling data from a previous session, it would end up highlighting arbitrary components on the page you're currently viewing (since ids are just auto-incremented numbers). We could use actual GUIDs- less likely to conflict, but I don't really want to add the extra overhead. Maybe instead we should track whether the profiler data was imported or recorded live, and...disable the hover feature for imported data.
I don't know. I might want to think on that a little, although if you have any ideas I"d be open to discussing them 😄
@@ -96,9 +99,13 @@ type Props = {| | |||
|}; | |||
|
|||
function CommitFlamegraph({chartData, commitTree, height, width}: Props) { | |||
const [hoveredFiberData, hoverFiber] = useState<number | null>(null); | |||
const [hoveredFiberData, setHoveredFiberData] = useState<number | null>(null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This Flow type looks wrong. (Looks like it's been wrong for a while though FWIW- which is a bit concerning.)
We aren't storing a number
in this state, but an object with id
and name
props (TooltipFiberData
).
const itemData = useMemo<ItemData>( | ||
() => ({ | ||
chartData, | ||
hoverFiber, | ||
isHovered: hoveredFiberData && hoveredFiberData.id, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this check not just hoveredFiberData !== null
?
@@ -140,7 +159,7 @@ function CommitFlamegraph({chartData, commitTree, height, width}: Props) { | |||
}), | |||
[ | |||
chartData, | |||
hoverFiber, | |||
setHoveredFiberData, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks wrong. The dependencies array has setHoveredFiberData
but the memoized value references hoveredFiberData
.
I wonder why our lint rule isn't complaining about this.
hoverFiber, | ||
isHovered: hoveredFiberData && hoveredFiberData.id, | ||
onElementMouseEnter: handleElementMouseEnter, | ||
onElementMouseLeave: handleElementMouseLeave, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks wrong. Neither handleElementMouseEnter
nor handleElementMouseLeave
are mentioned in the dependencies array.
I wonder why our lint rule isn't complaining about this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch
@@ -94,19 +97,35 @@ type Props = {| | |||
|}; | |||
|
|||
function CommitRanked({chartData, commitTree, height, width}: Props) { | |||
const [hoveredFiberData, hoverFiber] = useState<number | null>(null); | |||
const [hoveredFiberData, setHoveredFiberData] = useState<number | null>(null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as above wrt hook state type.
hoverFiber, | ||
isHovered: hoveredFiberData && hoveredFiberData.id, | ||
onElementMouseEnter: handleElementMouseEnter, | ||
onElementMouseLeave: handleElementMouseLeave, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as above wrt missing dependencies.
const itemData = useMemo<ItemData>( | ||
() => ({ | ||
chartData, | ||
hoverFiber, | ||
isHovered: hoveredFiberData && hoveredFiberData.id, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as above wrt hoveredFiberData !== null
Some follow up from my review yesterday. Turns out our Flow coverage was really broken for DevTools. Oops! Fixed with #18204. The "rules of hooks" lint rule isn't being run on this repo, but should be. I'll look to add it with a separate PR. |
Oh I see, I can also try to check it out if we are using it on all the packages |
@bvaughn Yeah, you are right, we can check if the element is imported, I think in the tooltip we already have information on that part (only if we are listening for changes for that), we can re-use the logic there for the highlighter too. |
@M-Izadmehr Would be great if we could get this landed. :-) |
@gaearon Yeah, please don't close this one, I was really busy in the past month and couldn't come back to this issue, I will try to pick it up in the weekend (thanks to quarantine, we have so much free time now:) ) |
Hey @M-Izadmehr, PR #18479 is is going to cause a bit of a conflict for you b'c it also separates the highlight behavior into a hook. Looks like the hook is the same as yours though, so it should be easy for you to rebase and just use it instead. Just wanted to give you a heads up! |
@M-Izadmehr Friendly ping :-) Do you think you might be able to get this over the finish line? |
Hey @M-Izadmehr can you please explain how you managed to request a review and not be a member at the same time? 🤔 |
@bl00mber I've reviewed several of your PRs in the past month or so 😄 It's important to keep in mind that there are only a half dozen or so React core members trying to keep up with PRs from > 1,000 contributors (while at the same time creating our own as well). |
@bvaughn yeah thanks, I've actually do not wanted to request a review now (may be only on stalled PRs), was just curious how the author of this PR is able to do it. |
This pull request has been automatically marked as stale. If this pull request is still relevant, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize reviewing it yet. Your contribution is very much appreciated. |
Closing this pull request after a prolonged period of inactivity. If this issue is still present in the latest release, please ask for this pull request to be reopened. Thank you! |
Summary: Fix #17928
Inside the devTools (Components) we have component highlighting, and by hovering the mouse on components it will highlight them in DOM. However, this feature was missing from
Profiler
(both FlameGraph Chart and Ranked Chart). The purpose of this PR is to add this functionality to the profiler.Demo