From be771109cac54d7f46b66a6123befc5dbed0a50e Mon Sep 17 00:00:00 2001 From: Mojtaba Izadmehr Date: Sun, 16 Feb 2020 22:59:08 +0100 Subject: [PATCH 01/11] Add tooltip component --- .../src/devtools/views/Components/Tooltip.css | 19 ++++++ .../src/devtools/views/Components/Tooltip.js | 51 +++++++++++++++ .../src/devtools/views/hooks.js | 63 +++++++++++++++++++ 3 files changed, 133 insertions(+) create mode 100644 packages/react-devtools-shared/src/devtools/views/Components/Tooltip.css create mode 100644 packages/react-devtools-shared/src/devtools/views/Components/Tooltip.js diff --git a/packages/react-devtools-shared/src/devtools/views/Components/Tooltip.css b/packages/react-devtools-shared/src/devtools/views/Components/Tooltip.css new file mode 100644 index 0000000000000..ab564e37d9f8b --- /dev/null +++ b/packages/react-devtools-shared/src/devtools/views/Components/Tooltip.css @@ -0,0 +1,19 @@ +.Tooltip { + position: absolute; + pointer-events: none; + border: none; + border-radius: 0.25rem; + padding: 0.25rem 0.5rem; + font-family: var(--font-family-sans); + font-size: 12px; + background-color: var(--color-tooltip-background); + color: var(--color-tooltip-text); + + /* Make sure this is above the DevTools, which are above the Overlay */ + z-index: 10000002; +} + +.Container { + width: -moz-max-content; + width: -webkit-max-content; +} diff --git a/packages/react-devtools-shared/src/devtools/views/Components/Tooltip.js b/packages/react-devtools-shared/src/devtools/views/Components/Tooltip.js new file mode 100644 index 0000000000000..dbb7e00de2691 --- /dev/null +++ b/packages/react-devtools-shared/src/devtools/views/Components/Tooltip.js @@ -0,0 +1,51 @@ +/** @flow */ + +import React, {useCallback, useRef, useState} from 'react'; +import {useSmartTooltip} from '../hooks'; + +import styles from './Tooltip.css'; + +const initialTooltipState = {height: 0, mouseX: 0, mouseY: 0, width: 0}; + +export default function Tooltip({children, label}: any) { + const containerRef = useRef(null); + const [tooltipState, setTooltipState] = useState(initialTooltipState); + const tooltipRef = useSmartTooltip(tooltipState); + + const onMouseMove = useCallback( + (event: SyntheticMouseEvent<*>) => { + setTooltipState(getTooltipPosition(containerRef.current, event)); + }, + [setTooltipState], + ); + + return ( +
+ {label !== null && ( +
+ {label} +
+ )} + {children} +
+ ); +} + +function getTooltipPosition( + relativeContainer, + mouseEvent: SyntheticMouseEvent<*>, +) { + if (relativeContainer !== null) { + const {height, top, width} = relativeContainer.getBoundingClientRect(); + + const mouseX = mouseEvent.clientX; + const mouseY = mouseEvent.clientY - top; + + return {height, mouseX, mouseY, width}; + } else { + return initialTooltipState; + } +} diff --git a/packages/react-devtools-shared/src/devtools/views/hooks.js b/packages/react-devtools-shared/src/devtools/views/hooks.js index a8fb43dd61a12..dfaca5f67ad9f 100644 --- a/packages/react-devtools-shared/src/devtools/views/hooks.js +++ b/packages/react-devtools-shared/src/devtools/views/hooks.js @@ -13,6 +13,7 @@ import { useEffect, useLayoutEffect, useReducer, + useRef, useState, } from 'react'; import { @@ -300,3 +301,65 @@ export function useSubscription({ return state.value; } + +export function useSmartTooltip({ + height, + mouseX, + mouseY, + width, +}: { + height: number, + mouseX: number, + mouseY: number, + width: number, +}) { + const TOOLTIP_OFFSET_X = 5; + const TOOLTIP_OFFSET_Y = 15; + const ref = useRef(null); + + useLayoutEffect(() => { + const element = ref.current; + + if (element != null) { + // Let's check the vertical position. + if (mouseY + TOOLTIP_OFFSET_Y + element.offsetHeight >= height) { + // The tooltip doesn't fit below the mouse cursor (which is our + // default strategy). Therefore we try to position it either above the + // mouse cursor or finally aligned with the window's top edge. + if (mouseY - TOOLTIP_OFFSET_Y - element.offsetHeight > 0) { + // We position the tooltip above the mouse cursor if it fits there. + element.style.top = `${mouseY - + element.offsetHeight - + TOOLTIP_OFFSET_Y}px`; + } else { + // Otherwise we align the tooltip with the window's top edge. + element.style.top = '0px'; + } + } else { + element.style.top = `${mouseY + TOOLTIP_OFFSET_Y}px`; + } + + // Now let's check the horizontal position. + if (mouseX + TOOLTIP_OFFSET_X + element.offsetWidth >= width) { + // The tooltip doesn't fit at the right of the mouse cursor (which is + // our default strategy). Therefore we try to position it either at the + // left of the mouse cursor or finally aligned with the window's left + // edge. + if (mouseX - TOOLTIP_OFFSET_X - element.offsetWidth > 0) { + // We position the tooltip at the left of the mouse cursor if it fits + // there. + element.style.left = `${mouseX - + element.offsetWidth - + TOOLTIP_OFFSET_X}px`; + } else { + // Otherwise, align the tooltip with the window's left edge. + element.style.left = '0px'; + } + } else { + element.style.left = `${mouseX + TOOLTIP_OFFSET_X * 2}px`; + } + } + }); + + return ref; +} From 9b5c730beae2f5dcb58981efb301d87a57b92d10 Mon Sep 17 00:00:00 2001 From: Mojtaba Izadmehr Date: Sun, 16 Feb 2020 22:59:52 +0100 Subject: [PATCH 02/11] Separate logic of ProfilerWhatChanged to a component --- .../views/Components/ProfilerWhatChanged.css | 30 ++++ .../views/Components/ProfilerWhatChanged.js | 138 ++++++++++++++++++ .../Profiler/SidebarSelectedFiberInfo.css | 21 +-- .../Profiler/SidebarSelectedFiberInfo.js | 135 +---------------- 4 files changed, 172 insertions(+), 152 deletions(-) create mode 100644 packages/react-devtools-shared/src/devtools/views/Components/ProfilerWhatChanged.css create mode 100644 packages/react-devtools-shared/src/devtools/views/Components/ProfilerWhatChanged.js diff --git a/packages/react-devtools-shared/src/devtools/views/Components/ProfilerWhatChanged.css b/packages/react-devtools-shared/src/devtools/views/Components/ProfilerWhatChanged.css new file mode 100644 index 0000000000000..1e0dd8e597015 --- /dev/null +++ b/packages/react-devtools-shared/src/devtools/views/Components/ProfilerWhatChanged.css @@ -0,0 +1,30 @@ +.Component { + margin-bottom: 1rem; +} + +.Item { + margin-top: 0.25rem; +} + +.Key { + font-family: var(--font-family-monospace); + font-size: var(--font-size-monospace-small); + line-height: 1; +} + +.Key:first-of-type::before { + content: ' ('; +} + +.Key::after { + content: ', '; +} + +.Key:last-of-type::after { + content: ')'; +} + +.Label { + font-weight: bold; + margin-bottom: 0.5rem; +} diff --git a/packages/react-devtools-shared/src/devtools/views/Components/ProfilerWhatChanged.js b/packages/react-devtools-shared/src/devtools/views/Components/ProfilerWhatChanged.js new file mode 100644 index 0000000000000..75846da1d11e6 --- /dev/null +++ b/packages/react-devtools-shared/src/devtools/views/Components/ProfilerWhatChanged.js @@ -0,0 +1,138 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +import React, {useContext} from 'react'; +import {ProfilerContext} from '../Profiler/ProfilerContext'; +import {StoreContext} from '../context'; + +import styles from './ProfilerWhatChanged.css'; + +type ProfilerWhatChangedProps = {| + fiberID: number, +|}; + +export default function ProfilerWhatChanged({ + fiberID, +}: ProfilerWhatChangedProps) { + const {profilerStore} = useContext(StoreContext); + const {rootID, selectedCommitIndex} = useContext(ProfilerContext); + + // TRICKY + // Handle edge case where no commit is selected because of a min-duration filter update. + // If the commit index is null, suspending for data below would throw an error. + // TODO (ProfilerContext) This check should not be necessary. + if (selectedCommitIndex === null) { + return null; + } + + const {changeDescriptions} = profilerStore.getCommitData( + ((rootID: any): number), + selectedCommitIndex, + ); + + if (changeDescriptions === null) { + return null; + } + + const changeDescription = changeDescriptions.get(fiberID); + if (changeDescription == null) { + return null; + } + + if (changeDescription.isFirstMount) { + return ( +
+ +
+ This is the first time the component rendered. +
+
+ ); + } + + const changes = []; + + if (changeDescription.context === true) { + changes.push( +
+ • Context changed +
, + ); + } else if ( + typeof changeDescription.context === 'object' && + changeDescription.context !== null && + changeDescription.context.length !== 0 + ) { + changes.push( +
+ • Context changed: + {changeDescription.context.map(key => ( + + {key} + + ))} +
, + ); + } + + if (changeDescription.didHooksChange) { + changes.push( +
+ • Hooks changed +
, + ); + } + + if ( + changeDescription.props !== null && + changeDescription.props.length !== 0 + ) { + changes.push( +
+ • Props changed: + {changeDescription.props.map(key => ( + + {key} + + ))} +
, + ); + } + + if ( + changeDescription.state !== null && + changeDescription.state.length !== 0 + ) { + changes.push( +
+ • State changed: + {changeDescription.state.map(key => ( + + {key} + + ))} +
, + ); + } + + if (changes.length === 0) { + changes.push( +
+ The parent component rendered. +
, + ); + } + + return ( +
+ + {changes} +
+ ); +} diff --git a/packages/react-devtools-shared/src/devtools/views/Profiler/SidebarSelectedFiberInfo.css b/packages/react-devtools-shared/src/devtools/views/Profiler/SidebarSelectedFiberInfo.css index 2ea9526d9653a..de19c10391653 100644 --- a/packages/react-devtools-shared/src/devtools/views/Profiler/SidebarSelectedFiberInfo.css +++ b/packages/react-devtools-shared/src/devtools/views/Profiler/SidebarSelectedFiberInfo.css @@ -42,6 +42,7 @@ padding: 0.25rem 0.5rem; color: var(--color-text); } + .Commit:focus, .Commit:hover { outline: none; @@ -52,25 +53,7 @@ background-color: var(--color-background-selected); color: var(--color-text-selected); } + .CurrentCommit:focus { outline: none; } - -.WhatChangedItem { - margin-top: 0.25rem; -} - -.WhatChangedKey { - font-family: var(--font-family-monospace); - font-size: var(--font-size-monospace-small); - line-height: 1; -} -.WhatChangedKey:first-of-type::before { - content: ' ('; -} -.WhatChangedKey::after { - content: ', '; -} -.WhatChangedKey:last-of-type::after { - content: ')'; -} diff --git a/packages/react-devtools-shared/src/devtools/views/Profiler/SidebarSelectedFiberInfo.js b/packages/react-devtools-shared/src/devtools/views/Profiler/SidebarSelectedFiberInfo.js index 595d0e0e17439..0cef165762a1e 100644 --- a/packages/react-devtools-shared/src/devtools/views/Profiler/SidebarSelectedFiberInfo.js +++ b/packages/react-devtools-shared/src/devtools/views/Profiler/SidebarSelectedFiberInfo.js @@ -8,7 +8,7 @@ */ import React, {Fragment, useContext} from 'react'; -import ProfilerStore from 'react-devtools-shared/src/devtools/ProfilerStore'; +import ProfilerWhatChanged from '../Components/ProfilerWhatChanged'; import {ProfilerContext} from './ProfilerContext'; import {formatDuration, formatTime} from './utils'; import {StoreContext} from '../context'; @@ -75,12 +75,7 @@ export default function SidebarSelectedFiberInfo(_: Props) {
- + {listItems.length > 0 && ( : {listItems} @@ -93,129 +88,3 @@ export default function SidebarSelectedFiberInfo(_: Props) { ); } - -type WhatChangedProps = {| - commitIndex: number | null, - fiberID: number, - profilerStore: ProfilerStore, - rootID: number, -|}; - -function WhatChanged({ - commitIndex, - fiberID, - profilerStore, - rootID, -}: WhatChangedProps) { - // TRICKY - // Handle edge case where no commit is selected because of a min-duration filter update. - // If the commit index is null, suspending for data below would throw an error. - // TODO (ProfilerContext) This check should not be necessary. - if (commitIndex === null) { - return null; - } - - const {changeDescriptions} = profilerStore.getCommitData( - ((rootID: any): number), - commitIndex, - ); - if (changeDescriptions === null) { - return null; - } - - const changeDescription = changeDescriptions.get(fiberID); - if (changeDescription == null) { - return null; - } - - if (changeDescription.isFirstMount) { - return ( -
- -
- This is the first time the component rendered. -
-
- ); - } - - const changes = []; - - if (changeDescription.context === true) { - changes.push( -
- • Context changed -
, - ); - } else if ( - typeof changeDescription.context === 'object' && - changeDescription.context !== null && - changeDescription.context.length !== 0 - ) { - changes.push( -
- • Context changed: - {changeDescription.context.map(key => ( - - {key} - - ))} -
, - ); - } - - if (changeDescription.didHooksChange) { - changes.push( -
- • Hooks changed -
, - ); - } - - if ( - changeDescription.props !== null && - changeDescription.props.length !== 0 - ) { - changes.push( -
- • Props changed: - {changeDescription.props.map(key => ( - - {key} - - ))} -
, - ); - } - - if ( - changeDescription.state !== null && - changeDescription.state.length !== 0 - ) { - changes.push( -
- • State changed: - {changeDescription.state.map(key => ( - - {key} - - ))} -
, - ); - } - - if (changes.length === 0) { - changes.push( -
- The parent component rendered. -
, - ); - } - - return ( -
- - {changes} -
- ); -} From 1cfcd33dd357d592e717c69670a01c860c48e238 Mon Sep 17 00:00:00 2001 From: Mojtaba Izadmehr Date: Sun, 16 Feb 2020 23:00:11 +0100 Subject: [PATCH 03/11] Add hovered Fiber info tooltip component --- .../views/Profiler/HoveredFiberInfo.css | 38 ++++++++++ .../views/Profiler/HoveredFiberInfo.js | 72 +++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 packages/react-devtools-shared/src/devtools/views/Profiler/HoveredFiberInfo.css create mode 100644 packages/react-devtools-shared/src/devtools/views/Profiler/HoveredFiberInfo.js diff --git a/packages/react-devtools-shared/src/devtools/views/Profiler/HoveredFiberInfo.css b/packages/react-devtools-shared/src/devtools/views/Profiler/HoveredFiberInfo.css new file mode 100644 index 0000000000000..14afb8d719e05 --- /dev/null +++ b/packages/react-devtools-shared/src/devtools/views/Profiler/HoveredFiberInfo.css @@ -0,0 +1,38 @@ +.Toolbar { + height: 2.25rem; + padding: 0 0.5rem; + flex: 0 0 auto; + display: flex; + align-items: center; + border-bottom: 1px solid var(--color-border); +} + +.Content { + padding: 0.5rem; + user-select: none; + overflow-y: auto; +} + +.Component { + flex: 1; + font-weight: bold; + font-family: var(--font-family-monospace); + font-size: var(--font-size-monospace-normal); + white-space: nowrap; + overflow-x: hidden; + text-overflow: ellipsis; +} + +.Label { + font-weight: bold; + margin-bottom: 0.5rem; +} + +.CurrentCommit { + display: block; + width: 100%; + text-align: left; + background: none; + border: none; + padding: 0.25rem 0.5rem; +} diff --git a/packages/react-devtools-shared/src/devtools/views/Profiler/HoveredFiberInfo.js b/packages/react-devtools-shared/src/devtools/views/Profiler/HoveredFiberInfo.js new file mode 100644 index 0000000000000..f85c39bcaf85d --- /dev/null +++ b/packages/react-devtools-shared/src/devtools/views/Profiler/HoveredFiberInfo.js @@ -0,0 +1,72 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +import React, {Fragment, useContext} from 'react'; +import {ProfilerContext} from './ProfilerContext'; +import {formatDuration, formatTime} from './utils'; +import ProfilerWhatChanged from '../Components/ProfilerWhatChanged'; +import {StoreContext} from '../context'; + +import styles from './HoveredFiberInfo.css'; + +import type {ChartNode} from './FlamegraphChartBuilder'; + +export type Props = { + fiberData: ChartNode, +}; + +export default function HoveredFiberInfo({fiberData}: Props) { + const {profilerStore} = useContext(StoreContext); + const {rootID, selectedCommitIndex} = useContext(ProfilerContext); + + const {id, name} = fiberData; + const {profilingCache} = profilerStore; + + const commitIndices = profilingCache.getFiberCommits({ + fiberID: ((id: any): number), + rootID: ((rootID: any): number), + }); + + const listItems = []; + let i = 0; + for (i = 0; i < commitIndices.length; i++) { + const commitIndex = commitIndices[i]; + if (selectedCommitIndex === commitIndex) { + const {duration, timestamp} = profilerStore.getCommitData( + ((rootID: any): number), + commitIndex, + ); + + listItems.push( +
+ {formatTime(timestamp)}s for {formatDuration(duration)}ms +
, + ); + } + } + + return ( + +
+
{name}
+
+
+ + {listItems.length > 0 && ( + + : {listItems} + + )} + {listItems.length === 0 && ( +
Did not render during this profiling session.
+ )} +
+
+ ); +} From edd6e8e4bfcc34beef0806b5f959413e3ce8870b Mon Sep 17 00:00:00 2001 From: Mojtaba Izadmehr Date: Sun, 16 Feb 2020 23:00:27 +0100 Subject: [PATCH 04/11] Add flame graph chart tooltip --- .../src/devtools/views/Profiler/ChartNode.js | 7 ++- .../views/Profiler/CommitFlamegraph.js | 51 +++++++++++++++---- .../Profiler/CommitFlamegraphListItem.js | 21 ++++++++ 3 files changed, 67 insertions(+), 12 deletions(-) diff --git a/packages/react-devtools-shared/src/devtools/views/Profiler/ChartNode.js b/packages/react-devtools-shared/src/devtools/views/Profiler/ChartNode.js index 4a85d18fe8478..b1e677cf8d966 100644 --- a/packages/react-devtools-shared/src/devtools/views/Profiler/ChartNode.js +++ b/packages/react-devtools-shared/src/devtools/views/Profiler/ChartNode.js @@ -18,6 +18,8 @@ type Props = {| label: string, onClick: (event: SyntheticMouseEvent<*>) => mixed, onDoubleClick?: (event: SyntheticMouseEvent<*>) => mixed, + onMouseOver: (event: SyntheticMouseEvent<*>) => mixed, + onMouseOut: (event: SyntheticMouseEvent<*>) => mixed, placeLabelAboveNode?: boolean, textStyle?: Object, width: number, @@ -33,6 +35,8 @@ export default function ChartNode({ isDimmed = false, label, onClick, + onMouseOver, + onMouseOut, onDoubleClick, textStyle, width, @@ -41,12 +45,13 @@ export default function ChartNode({ }: Props) { return ( - {label} void, scaleX: (value: number, fallbackValue: number) => number, selectedChartNode: ChartNode | null, selectedChartNodeIndex: number, @@ -91,6 +100,7 @@ type Props = {| |}; function CommitFlamegraph({chartData, commitTree, height, width}: Props) { + const [hoveredFiberData, hoverFiber] = useState(null); const {lineHeight} = useContext(SettingsContext); const {selectFiber, selectedFiberID} = useContext(ProfilerContext); @@ -118,6 +128,7 @@ function CommitFlamegraph({chartData, commitTree, height, width}: Props) { const itemData = useMemo( () => ({ chartData, + hoverFiber, scaleX: scale( 0, selectedChartNode !== null @@ -131,19 +142,37 @@ function CommitFlamegraph({chartData, commitTree, height, width}: Props) { selectFiber, width, }), - [chartData, selectedChartNode, selectedChartNodeIndex, selectFiber, width], + [ + chartData, + hoverFiber, + selectedChartNode, + selectedChartNodeIndex, + selectFiber, + width, + ], + ); + + // Tooltip used to show summary of fiber info on hover + const tooltipLabel = useMemo( + () => + hoveredFiberData !== null ? ( + + ) : null, + [hoveredFiberData], ); return ( - - {CommitFlamegraphListItem} - + + + {CommitFlamegraphListItem} + + ); } diff --git a/packages/react-devtools-shared/src/devtools/views/Profiler/CommitFlamegraphListItem.js b/packages/react-devtools-shared/src/devtools/views/Profiler/CommitFlamegraphListItem.js index 66d2db36962c4..589a000e10c30 100644 --- a/packages/react-devtools-shared/src/devtools/views/Profiler/CommitFlamegraphListItem.js +++ b/packages/react-devtools-shared/src/devtools/views/Profiler/CommitFlamegraphListItem.js @@ -14,6 +14,7 @@ import {getGradientColor} from './utils'; import ChartNode from './ChartNode'; import {SettingsContext} from '../Settings/SettingsContext'; +import type {ChartNode as ChartNodeType} from './FlamegraphChartBuilder'; import type {ItemData} from './CommitFlamegraph'; type Props = { @@ -26,6 +27,7 @@ type Props = { function CommitFlamegraphListItem({data, index, style}: Props) { const { chartData, + hoverFiber, scaleX, selectedChartNode, selectedChartNodeIndex, @@ -35,6 +37,7 @@ function CommitFlamegraphListItem({data, index, style}: Props) { const {renderPathNodes, maxSelfDuration, rows} = chartData; const {lineHeight} = useContext(SettingsContext); + const handleClick = useCallback( (event: SyntheticMouseEvent<*>, id: number, name: string) => { event.stopPropagation(); @@ -43,6 +46,22 @@ function CommitFlamegraphListItem({data, index, style}: Props) { [selectFiber], ); + const handleMouseOver = useCallback( + (event: SyntheticMouseEvent<*>, nodeData: ChartNodeType) => { + event.stopPropagation(); + hoverFiber(nodeData); + }, + [hoverFiber], + ); + + const handleMouseOut = useCallback( + (event: SyntheticMouseEvent<*>, nodeData: ChartNodeType) => { + event.stopPropagation(); + hoverFiber(null); + }, + [hoverFiber], + ); + // List items are absolutely positioned using the CSS "top" attribute. // The "left" value will always be 0. // Since height is fixed, and width is based on the node's duration, @@ -104,6 +123,8 @@ function CommitFlamegraphListItem({data, index, style}: Props) { key={id} label={label} onClick={event => handleClick(event, id, name)} + onMouseOver={event => handleMouseOver(event, chartNode)} + onMouseOut={event => handleMouseOut(event, chartNode)} textStyle={{color: textColor}} width={nodeWidth} x={nodeOffset - selectedNodeOffset} From 255e741c626a1d97ba4a8dc7fcaa1527fb6f473f Mon Sep 17 00:00:00 2001 From: Mojtaba Izadmehr Date: Sun, 16 Feb 2020 23:00:35 +0100 Subject: [PATCH 05/11] Add commit ranked list tooltip --- .../devtools/views/Profiler/CommitRanked.js | 37 ++++++++++++++----- .../views/Profiler/CommitRankedListItem.js | 28 +++++++++++++- 2 files changed, 54 insertions(+), 11 deletions(-) diff --git a/packages/react-devtools-shared/src/devtools/views/Profiler/CommitRanked.js b/packages/react-devtools-shared/src/devtools/views/Profiler/CommitRanked.js index f230f67359920..43e39a2c59476 100644 --- a/packages/react-devtools-shared/src/devtools/views/Profiler/CommitRanked.js +++ b/packages/react-devtools-shared/src/devtools/views/Profiler/CommitRanked.js @@ -7,15 +7,17 @@ * @flow */ -import React, {useCallback, useContext, useMemo} from 'react'; +import React, {useCallback, useContext, useMemo, useState} from 'react'; import AutoSizer from 'react-virtualized-auto-sizer'; import {FixedSizeList} from 'react-window'; import {ProfilerContext} from './ProfilerContext'; import NoCommitData from './NoCommitData'; import CommitRankedListItem from './CommitRankedListItem'; +import HoveredFiberInfo from './HoveredFiberInfo'; import {scale} from './utils'; import {StoreContext} from '../context'; import {SettingsContext} from '../Settings/SettingsContext'; +import Tooltip from '../Components/Tooltip'; import styles from './CommitRanked.css'; @@ -24,6 +26,7 @@ import type {CommitTree} from './types'; export type ItemData = {| chartData: ChartData, + hoverFiber: (id: number | null, fiberData: ChartNode | null) => void, scaleX: (value: number, fallbackValue: number) => number, selectedFiberID: number | null, selectedFiberIndex: number, @@ -89,6 +92,7 @@ type Props = {| |}; function CommitRanked({chartData, commitTree, height, width}: Props) { + const [hoveredFiberData, hoverFiber] = useState(null); const {lineHeight} = useContext(SettingsContext); const {selectedFiberID, selectFiber} = useContext(ProfilerContext); @@ -100,6 +104,7 @@ function CommitRanked({chartData, commitTree, height, width}: Props) { const itemData = useMemo( () => ({ chartData, + hoverFiber, scaleX: scale(0, chartData.nodes[selectedFiberIndex].value, 0, width), selectedFiberID, selectedFiberIndex, @@ -109,16 +114,28 @@ function CommitRanked({chartData, commitTree, height, width}: Props) { [chartData, selectedFiberID, selectedFiberIndex, selectFiber, width], ); + // Tooltip used to show summary of fiber info on hover + const tooltipLabel = useMemo( + () => + hoveredFiberData !== null ? ( + + ) : null, + [hoveredFiberData], + ); + return ( - - {CommitRankedListItem} - + + + {CommitRankedListItem} + + > + ); } diff --git a/packages/react-devtools-shared/src/devtools/views/Profiler/CommitRankedListItem.js b/packages/react-devtools-shared/src/devtools/views/Profiler/CommitRankedListItem.js index 8c46e7de2730b..041ccc97fd45c 100644 --- a/packages/react-devtools-shared/src/devtools/views/Profiler/CommitRankedListItem.js +++ b/packages/react-devtools-shared/src/devtools/views/Profiler/CommitRankedListItem.js @@ -14,6 +14,7 @@ import {getGradientColor} from './utils'; import ChartNode from './ChartNode'; import {SettingsContext} from '../Settings/SettingsContext'; +import type {ChartData} from './RankedChartBuilder'; import type {ItemData} from './CommitRanked'; type Props = { @@ -24,7 +25,14 @@ type Props = { }; function CommitRankedListItem({data, index, style}: Props) { - const {chartData, scaleX, selectedFiberIndex, selectFiber, width} = data; + const { + chartData, + hoverFiber, + scaleX, + selectedFiberIndex, + selectFiber, + width, + } = data; const node = chartData.nodes[index]; @@ -38,6 +46,22 @@ function CommitRankedListItem({data, index, style}: Props) { [node, selectFiber], ); + const handleMouseOver = useCallback( + (event: SyntheticMouseEvent<*>, nodeData: ChartData) => { + event.stopPropagation(); + hoverFiber(nodeData); + }, + [hoverFiber], + ); + + const handleMouseOut = useCallback( + (event: SyntheticMouseEvent<*>, nodeData: ChartData) => { + event.stopPropagation(); + hoverFiber(null); + }, + [hoverFiber], + ); + // List items are absolutely positioned using the CSS "top" attribute. // The "left" value will always be 0. // Since height is fixed, and width is based on the node's duration, @@ -52,6 +76,8 @@ function CommitRankedListItem({data, index, style}: Props) { key={node.id} label={node.label} onClick={handleClick} + onMouseOver={event => handleMouseOver(event, node)} + onMouseOut={event => handleMouseOut(event, node)} width={Math.max(minBarWidth, scaleX(node.value, width))} x={0} y={top} From 8247667e697e774fb241c08d78a8dcf9be84abeb Mon Sep 17 00:00:00 2001 From: Mojtaba Izadmehr Date: Sun, 16 Feb 2020 23:35:17 +0100 Subject: [PATCH 06/11] Fix flow issues --- .../src/devtools/views/Profiler/CommitFlamegraph.js | 3 ++- .../views/Profiler/CommitFlamegraphListItem.js | 7 ++++--- .../src/devtools/views/Profiler/CommitRanked.js | 3 ++- .../devtools/views/Profiler/CommitRankedListItem.js | 11 ++++++----- .../src/devtools/views/Profiler/HoveredFiberInfo.js | 5 +++++ 5 files changed, 19 insertions(+), 10 deletions(-) diff --git a/packages/react-devtools-shared/src/devtools/views/Profiler/CommitFlamegraph.js b/packages/react-devtools-shared/src/devtools/views/Profiler/CommitFlamegraph.js index b88c10793580e..e4daf92bf7662 100644 --- a/packages/react-devtools-shared/src/devtools/views/Profiler/CommitFlamegraph.js +++ b/packages/react-devtools-shared/src/devtools/views/Profiler/CommitFlamegraph.js @@ -27,12 +27,13 @@ import Tooltip from '../Components/Tooltip'; import styles from './CommitFlamegraph.css'; +import type {TooltipFiberData} from './HoveredFiberInfo'; import type {ChartData, ChartNode} from './FlamegraphChartBuilder'; import type {CommitTree} from './types'; export type ItemData = {| chartData: ChartData, - hoverFiber: (id: number | null, fiberData: ChartNode | null) => void, + hoverFiber: (fiberData: TooltipFiberData | null) => void, scaleX: (value: number, fallbackValue: number) => number, selectedChartNode: ChartNode | null, selectedChartNodeIndex: number, diff --git a/packages/react-devtools-shared/src/devtools/views/Profiler/CommitFlamegraphListItem.js b/packages/react-devtools-shared/src/devtools/views/Profiler/CommitFlamegraphListItem.js index 589a000e10c30..04920026ec6a0 100644 --- a/packages/react-devtools-shared/src/devtools/views/Profiler/CommitFlamegraphListItem.js +++ b/packages/react-devtools-shared/src/devtools/views/Profiler/CommitFlamegraphListItem.js @@ -48,14 +48,15 @@ function CommitFlamegraphListItem({data, index, style}: Props) { const handleMouseOver = useCallback( (event: SyntheticMouseEvent<*>, nodeData: ChartNodeType) => { + const {id, name} = nodeData; event.stopPropagation(); - hoverFiber(nodeData); + hoverFiber({id, name}); }, [hoverFiber], ); const handleMouseOut = useCallback( - (event: SyntheticMouseEvent<*>, nodeData: ChartNodeType) => { + (event: SyntheticMouseEvent<*>) => { event.stopPropagation(); hoverFiber(null); }, @@ -124,7 +125,7 @@ function CommitFlamegraphListItem({data, index, style}: Props) { label={label} onClick={event => handleClick(event, id, name)} onMouseOver={event => handleMouseOver(event, chartNode)} - onMouseOut={event => handleMouseOut(event, chartNode)} + onMouseOut={event => handleMouseOut(event)} textStyle={{color: textColor}} width={nodeWidth} x={nodeOffset - selectedNodeOffset} diff --git a/packages/react-devtools-shared/src/devtools/views/Profiler/CommitRanked.js b/packages/react-devtools-shared/src/devtools/views/Profiler/CommitRanked.js index 43e39a2c59476..89bd0d8e82198 100644 --- a/packages/react-devtools-shared/src/devtools/views/Profiler/CommitRanked.js +++ b/packages/react-devtools-shared/src/devtools/views/Profiler/CommitRanked.js @@ -21,12 +21,13 @@ import Tooltip from '../Components/Tooltip'; import styles from './CommitRanked.css'; +import type {TooltipFiberData} from './HoveredFiberInfo'; import type {ChartData} from './RankedChartBuilder'; import type {CommitTree} from './types'; export type ItemData = {| chartData: ChartData, - hoverFiber: (id: number | null, fiberData: ChartNode | null) => void, + hoverFiber: (fiberData: TooltipFiberData | null) => void, scaleX: (value: number, fallbackValue: number) => number, selectedFiberID: number | null, selectedFiberIndex: number, diff --git a/packages/react-devtools-shared/src/devtools/views/Profiler/CommitRankedListItem.js b/packages/react-devtools-shared/src/devtools/views/Profiler/CommitRankedListItem.js index 041ccc97fd45c..4899760a63ec1 100644 --- a/packages/react-devtools-shared/src/devtools/views/Profiler/CommitRankedListItem.js +++ b/packages/react-devtools-shared/src/devtools/views/Profiler/CommitRankedListItem.js @@ -14,7 +14,7 @@ import {getGradientColor} from './utils'; import ChartNode from './ChartNode'; import {SettingsContext} from '../Settings/SettingsContext'; -import type {ChartData} from './RankedChartBuilder'; +import type {ChartNode as ChartNodeType} from './RankedChartBuilder'; import type {ItemData} from './CommitRanked'; type Props = { @@ -47,15 +47,16 @@ function CommitRankedListItem({data, index, style}: Props) { ); const handleMouseOver = useCallback( - (event: SyntheticMouseEvent<*>, nodeData: ChartData) => { + (event: SyntheticMouseEvent<*>, nodeData: ChartNodeType) => { + const {id, name} = nodeData; event.stopPropagation(); - hoverFiber(nodeData); + hoverFiber({id, name}); }, [hoverFiber], ); const handleMouseOut = useCallback( - (event: SyntheticMouseEvent<*>, nodeData: ChartData) => { + (event: SyntheticMouseEvent<*>) => { event.stopPropagation(); hoverFiber(null); }, @@ -77,7 +78,7 @@ function CommitRankedListItem({data, index, style}: Props) { label={node.label} onClick={handleClick} onMouseOver={event => handleMouseOver(event, node)} - onMouseOut={event => handleMouseOut(event, node)} + onMouseOut={event => handleMouseOut(event)} width={Math.max(minBarWidth, scaleX(node.value, width))} x={0} y={top} diff --git a/packages/react-devtools-shared/src/devtools/views/Profiler/HoveredFiberInfo.js b/packages/react-devtools-shared/src/devtools/views/Profiler/HoveredFiberInfo.js index f85c39bcaf85d..72a893a0e703f 100644 --- a/packages/react-devtools-shared/src/devtools/views/Profiler/HoveredFiberInfo.js +++ b/packages/react-devtools-shared/src/devtools/views/Profiler/HoveredFiberInfo.js @@ -17,6 +17,11 @@ import styles from './HoveredFiberInfo.css'; import type {ChartNode} from './FlamegraphChartBuilder'; +export type TooltipFiberData = {| + id: number, + name: string, +|}; + export type Props = { fiberData: ChartNode, }; From 4995ac9520fe21bb5a4156e8833673ec1b9f680c Mon Sep 17 00:00:00 2001 From: Mojtaba Izadmehr Date: Sun, 16 Feb 2020 23:45:07 +0100 Subject: [PATCH 07/11] Minor improvement in filter --- .../src/devtools/views/Profiler/HoveredFiberInfo.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/react-devtools-shared/src/devtools/views/Profiler/HoveredFiberInfo.js b/packages/react-devtools-shared/src/devtools/views/Profiler/HoveredFiberInfo.js index 72a893a0e703f..9f22c13c4b461 100644 --- a/packages/react-devtools-shared/src/devtools/views/Profiler/HoveredFiberInfo.js +++ b/packages/react-devtools-shared/src/devtools/views/Profiler/HoveredFiberInfo.js @@ -53,6 +53,7 @@ export default function HoveredFiberInfo({fiberData}: Props) { {formatTime(timestamp)}s for {formatDuration(duration)}ms
, ); + break; } } From be5f04ee0738641b96495ded3dde0a97428f8741 Mon Sep 17 00:00:00 2001 From: Mojtaba Izadmehr Date: Wed, 19 Feb 2020 02:21:38 +0100 Subject: [PATCH 08/11] Fix flickering issue --- .../src/devtools/views/Components/Tooltip.css | 7 +- .../src/devtools/views/Components/Tooltip.js | 91 +++++++++++++++---- .../src/devtools/views/hooks.js | 62 ------------- 3 files changed, 79 insertions(+), 81 deletions(-) diff --git a/packages/react-devtools-shared/src/devtools/views/Components/Tooltip.css b/packages/react-devtools-shared/src/devtools/views/Components/Tooltip.css index ab564e37d9f8b..2d2bbaf34ea38 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/Tooltip.css +++ b/packages/react-devtools-shared/src/devtools/views/Components/Tooltip.css @@ -8,11 +8,16 @@ font-size: 12px; background-color: var(--color-tooltip-background); color: var(--color-tooltip-text); - + opacity: 1; /* Make sure this is above the DevTools, which are above the Overlay */ z-index: 10000002; } +.Tooltip.hidden { + opacity: 0; +} + + .Container { width: -moz-max-content; width: -webkit-max-content; diff --git a/packages/react-devtools-shared/src/devtools/views/Components/Tooltip.js b/packages/react-devtools-shared/src/devtools/views/Components/Tooltip.js index dbb7e00de2691..5be379ee668da 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/Tooltip.js +++ b/packages/react-devtools-shared/src/devtools/views/Components/Tooltip.js @@ -1,7 +1,6 @@ /** @flow */ -import React, {useCallback, useRef, useState} from 'react'; -import {useSmartTooltip} from '../hooks'; +import React, {useRef} from 'react'; import styles from './Tooltip.css'; @@ -9,32 +8,88 @@ const initialTooltipState = {height: 0, mouseX: 0, mouseY: 0, width: 0}; export default function Tooltip({children, label}: any) { const containerRef = useRef(null); - const [tooltipState, setTooltipState] = useState(initialTooltipState); - const tooltipRef = useSmartTooltip(tooltipState); - - const onMouseMove = useCallback( - (event: SyntheticMouseEvent<*>) => { - setTooltipState(getTooltipPosition(containerRef.current, event)); - }, - [setTooltipState], - ); + const tooltipRef = useRef(null); + + // update the position of the tooltip based on current mouse position + const updateTooltipPosition = (event: SyntheticMouseEvent<*>) => { + const element = tooltipRef.current; + if (element != null) { + // first find the mouse position + const mousePosition = getMousePosition(containerRef.current, event); + // use the mouse position to find the position of tooltip + const {left, top} = getTooltipPosition(element, mousePosition); + // update tooltip position + element.style.left = left; + element.style.top = top; + } + }; + + const onMouseMove = (event: SyntheticMouseEvent<*>) => { + updateTooltipPosition(event); + }; + + const tooltipClassName = label === null ? styles.hidden : ''; return (
- {label !== null && ( -
- {label} -
- )} +
+ {label} +
{children}
); } -function getTooltipPosition( +// Method used to find the position of the tooltip based on current mouse position +function getTooltipPosition(element, mousePosition) { + const {height, mouseX, mouseY, width} = mousePosition; + const TOOLTIP_OFFSET_X = 5; + const TOOLTIP_OFFSET_Y = 15; + let top = 0; + let left = 0; + + // Let's check the vertical position. + if (mouseY + TOOLTIP_OFFSET_Y + element.offsetHeight >= height) { + // The tooltip doesn't fit below the mouse cursor (which is our + // default strategy). Therefore we try to position it either above the + // mouse cursor or finally aligned with the window's top edge. + if (mouseY - TOOLTIP_OFFSET_Y - element.offsetHeight > 0) { + // We position the tooltip above the mouse cursor if it fits there. + top = `${mouseY - element.offsetHeight - TOOLTIP_OFFSET_Y}px`; + } else { + // Otherwise we align the tooltip with the window's top edge. + top = '0px'; + } + } else { + top = `${mouseY + TOOLTIP_OFFSET_Y}px`; + } + + // Now let's check the horizontal position. + if (mouseX + TOOLTIP_OFFSET_X + element.offsetWidth >= width) { + // The tooltip doesn't fit at the right of the mouse cursor (which is + // our default strategy). Therefore we try to position it either at the + // left of the mouse cursor or finally aligned with the window's left + // edge. + if (mouseX - TOOLTIP_OFFSET_X - element.offsetWidth > 0) { + // We position the tooltip at the left of the mouse cursor if it fits + // there. + left = `${mouseX - element.offsetWidth - TOOLTIP_OFFSET_X}px`; + } else { + // Otherwise, align the tooltip with the window's left edge. + left = '0px'; + } + } else { + left = `${mouseX + TOOLTIP_OFFSET_X * 2}px`; + } + + return {left, top}; +} + +// method used to find the current mouse position inside the container +function getMousePosition( relativeContainer, mouseEvent: SyntheticMouseEvent<*>, ) { diff --git a/packages/react-devtools-shared/src/devtools/views/hooks.js b/packages/react-devtools-shared/src/devtools/views/hooks.js index dfaca5f67ad9f..af69fea1019bb 100644 --- a/packages/react-devtools-shared/src/devtools/views/hooks.js +++ b/packages/react-devtools-shared/src/devtools/views/hooks.js @@ -301,65 +301,3 @@ export function useSubscription({ return state.value; } - -export function useSmartTooltip({ - height, - mouseX, - mouseY, - width, -}: { - height: number, - mouseX: number, - mouseY: number, - width: number, -}) { - const TOOLTIP_OFFSET_X = 5; - const TOOLTIP_OFFSET_Y = 15; - const ref = useRef(null); - - useLayoutEffect(() => { - const element = ref.current; - - if (element != null) { - // Let's check the vertical position. - if (mouseY + TOOLTIP_OFFSET_Y + element.offsetHeight >= height) { - // The tooltip doesn't fit below the mouse cursor (which is our - // default strategy). Therefore we try to position it either above the - // mouse cursor or finally aligned with the window's top edge. - if (mouseY - TOOLTIP_OFFSET_Y - element.offsetHeight > 0) { - // We position the tooltip above the mouse cursor if it fits there. - element.style.top = `${mouseY - - element.offsetHeight - - TOOLTIP_OFFSET_Y}px`; - } else { - // Otherwise we align the tooltip with the window's top edge. - element.style.top = '0px'; - } - } else { - element.style.top = `${mouseY + TOOLTIP_OFFSET_Y}px`; - } - - // Now let's check the horizontal position. - if (mouseX + TOOLTIP_OFFSET_X + element.offsetWidth >= width) { - // The tooltip doesn't fit at the right of the mouse cursor (which is - // our default strategy). Therefore we try to position it either at the - // left of the mouse cursor or finally aligned with the window's left - // edge. - if (mouseX - TOOLTIP_OFFSET_X - element.offsetWidth > 0) { - // We position the tooltip at the left of the mouse cursor if it fits - // there. - element.style.left = `${mouseX - - element.offsetWidth - - TOOLTIP_OFFSET_X}px`; - } else { - // Otherwise, align the tooltip with the window's left edge. - element.style.left = '0px'; - } - } else { - element.style.left = `${mouseX + TOOLTIP_OFFSET_X * 2}px`; - } - } - }); - - return ref; -} From e1e114c7fd1d2ce28481d4e8ff5a070ba99142f0 Mon Sep 17 00:00:00 2001 From: Mojtaba Izadmehr Date: Wed, 19 Feb 2020 02:40:41 +0100 Subject: [PATCH 09/11] Resolved issues on useCallbacks and mouse event listeners --- .../src/devtools/views/Profiler/ChartNode.js | 12 ++++----- .../Profiler/CommitFlamegraphListItem.js | 26 +++++++----------- .../views/Profiler/CommitRankedListItem.js | 27 +++++++------------ .../views/Profiler/HoveredFiberInfo.js | 21 +++++++-------- 4 files changed, 34 insertions(+), 52 deletions(-) diff --git a/packages/react-devtools-shared/src/devtools/views/Profiler/ChartNode.js b/packages/react-devtools-shared/src/devtools/views/Profiler/ChartNode.js index b1e677cf8d966..3f7c7b4a1f732 100644 --- a/packages/react-devtools-shared/src/devtools/views/Profiler/ChartNode.js +++ b/packages/react-devtools-shared/src/devtools/views/Profiler/ChartNode.js @@ -18,8 +18,8 @@ type Props = {| label: string, onClick: (event: SyntheticMouseEvent<*>) => mixed, onDoubleClick?: (event: SyntheticMouseEvent<*>) => mixed, - onMouseOver: (event: SyntheticMouseEvent<*>) => mixed, - onMouseOut: (event: SyntheticMouseEvent<*>) => mixed, + onMouseEnter: (event: SyntheticMouseEvent<*>) => mixed, + onMouseLeave: (event: SyntheticMouseEvent<*>) => mixed, placeLabelAboveNode?: boolean, textStyle?: Object, width: number, @@ -35,8 +35,8 @@ export default function ChartNode({ isDimmed = false, label, onClick, - onMouseOver, - onMouseOut, + onMouseEnter, + onMouseLeave, onDoubleClick, textStyle, width, @@ -50,8 +50,8 @@ export default function ChartNode({ height={height} fill={color} onClick={onClick} - onMouseOver={onMouseOver} - onMouseOut={onMouseOut} + onMouseEnter={onMouseEnter} + onMouseLeave={onMouseLeave} onDoubleClick={onDoubleClick} className={styles.Rect} style={{ diff --git a/packages/react-devtools-shared/src/devtools/views/Profiler/CommitFlamegraphListItem.js b/packages/react-devtools-shared/src/devtools/views/Profiler/CommitFlamegraphListItem.js index 04920026ec6a0..bf511d879326e 100644 --- a/packages/react-devtools-shared/src/devtools/views/Profiler/CommitFlamegraphListItem.js +++ b/packages/react-devtools-shared/src/devtools/views/Profiler/CommitFlamegraphListItem.js @@ -46,22 +46,14 @@ function CommitFlamegraphListItem({data, index, style}: Props) { [selectFiber], ); - const handleMouseOver = useCallback( - (event: SyntheticMouseEvent<*>, nodeData: ChartNodeType) => { - const {id, name} = nodeData; - event.stopPropagation(); - hoverFiber({id, name}); - }, - [hoverFiber], - ); + const handleMouseEnter = (nodeData: ChartNodeType) => { + const {id, name} = nodeData; + hoverFiber({id, name}); + }; - const handleMouseOut = useCallback( - (event: SyntheticMouseEvent<*>) => { - event.stopPropagation(); - hoverFiber(null); - }, - [hoverFiber], - ); + const handleMouseLeave = () => { + hoverFiber(null); + }; // List items are absolutely positioned using the CSS "top" attribute. // The "left" value will always be 0. @@ -124,8 +116,8 @@ function CommitFlamegraphListItem({data, index, style}: Props) { key={id} label={label} onClick={event => handleClick(event, id, name)} - onMouseOver={event => handleMouseOver(event, chartNode)} - onMouseOut={event => handleMouseOut(event)} + onMouseEnter={() => handleMouseEnter(chartNode)} + onMouseLeave={handleMouseLeave} textStyle={{color: textColor}} width={nodeWidth} x={nodeOffset - selectedNodeOffset} diff --git a/packages/react-devtools-shared/src/devtools/views/Profiler/CommitRankedListItem.js b/packages/react-devtools-shared/src/devtools/views/Profiler/CommitRankedListItem.js index 4899760a63ec1..d8856d9bf1655 100644 --- a/packages/react-devtools-shared/src/devtools/views/Profiler/CommitRankedListItem.js +++ b/packages/react-devtools-shared/src/devtools/views/Profiler/CommitRankedListItem.js @@ -14,7 +14,6 @@ import {getGradientColor} from './utils'; import ChartNode from './ChartNode'; import {SettingsContext} from '../Settings/SettingsContext'; -import type {ChartNode as ChartNodeType} from './RankedChartBuilder'; import type {ItemData} from './CommitRanked'; type Props = { @@ -46,22 +45,14 @@ function CommitRankedListItem({data, index, style}: Props) { [node, selectFiber], ); - const handleMouseOver = useCallback( - (event: SyntheticMouseEvent<*>, nodeData: ChartNodeType) => { - const {id, name} = nodeData; - event.stopPropagation(); - hoverFiber({id, name}); - }, - [hoverFiber], - ); + const handleMouseEnter = useCallback(() => { + const {id, name} = node; + hoverFiber({id, name}); + }, [node]); - const handleMouseOut = useCallback( - (event: SyntheticMouseEvent<*>) => { - event.stopPropagation(); - hoverFiber(null); - }, - [hoverFiber], - ); + const handleMouseLeave = () => { + hoverFiber(null); + }; // List items are absolutely positioned using the CSS "top" attribute. // The "left" value will always be 0. @@ -77,8 +68,8 @@ function CommitRankedListItem({data, index, style}: Props) { key={node.id} label={node.label} onClick={handleClick} - onMouseOver={event => handleMouseOver(event, node)} - onMouseOut={event => handleMouseOut(event)} + onMouseEnter={handleMouseEnter} + onMouseLeave={handleMouseLeave} width={Math.max(minBarWidth, scaleX(node.value, width))} x={0} y={top} diff --git a/packages/react-devtools-shared/src/devtools/views/Profiler/HoveredFiberInfo.js b/packages/react-devtools-shared/src/devtools/views/Profiler/HoveredFiberInfo.js index 9f22c13c4b461..d6b102cd5f2de 100644 --- a/packages/react-devtools-shared/src/devtools/views/Profiler/HoveredFiberInfo.js +++ b/packages/react-devtools-shared/src/devtools/views/Profiler/HoveredFiberInfo.js @@ -38,7 +38,7 @@ export default function HoveredFiberInfo({fiberData}: Props) { rootID: ((rootID: any): number), }); - const listItems = []; + let renderDurationInfo; let i = 0; for (i = 0; i < commitIndices.length; i++) { const commitIndex = commitIndices[i]; @@ -48,11 +48,15 @@ export default function HoveredFiberInfo({fiberData}: Props) { commitIndex, ); - listItems.push( -
- {formatTime(timestamp)}s for {formatDuration(duration)}ms -
, + renderDurationInfo = ( + + +
+ {formatTime(timestamp)}s for {formatDuration(duration)}ms +
+
); + break; } } @@ -64,12 +68,7 @@ export default function HoveredFiberInfo({fiberData}: Props) {
- {listItems.length > 0 && ( - - : {listItems} - - )} - {listItems.length === 0 && ( + {renderDurationInfo || (
Did not render during this profiling session.
)}
From 0bd6e07a970fc711855b184ca222ee6d1897ade3 Mon Sep 17 00:00:00 2001 From: Mojtaba Izadmehr Date: Wed, 19 Feb 2020 02:43:15 +0100 Subject: [PATCH 10/11] Fix lints --- packages/react-devtools-shared/src/devtools/views/hooks.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/react-devtools-shared/src/devtools/views/hooks.js b/packages/react-devtools-shared/src/devtools/views/hooks.js index af69fea1019bb..a8fb43dd61a12 100644 --- a/packages/react-devtools-shared/src/devtools/views/hooks.js +++ b/packages/react-devtools-shared/src/devtools/views/hooks.js @@ -13,7 +13,6 @@ import { useEffect, useLayoutEffect, useReducer, - useRef, useState, } from 'react'; import { From 20caae7b2031af08e7c426e4eb1eb2ddf8039ddd Mon Sep 17 00:00:00 2001 From: Mojtaba Izadmehr Date: Wed, 19 Feb 2020 12:46:22 +0100 Subject: [PATCH 11/11] Remove unnecessary useCallback --- .../src/devtools/views/Profiler/CommitRankedListItem.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/react-devtools-shared/src/devtools/views/Profiler/CommitRankedListItem.js b/packages/react-devtools-shared/src/devtools/views/Profiler/CommitRankedListItem.js index d8856d9bf1655..80f6dbade6e29 100644 --- a/packages/react-devtools-shared/src/devtools/views/Profiler/CommitRankedListItem.js +++ b/packages/react-devtools-shared/src/devtools/views/Profiler/CommitRankedListItem.js @@ -40,15 +40,16 @@ function CommitRankedListItem({data, index, style}: Props) { const handleClick = useCallback( event => { event.stopPropagation(); - selectFiber(node.id, node.name); + const {id, name} = node; + selectFiber(id, name); }, [node, selectFiber], ); - const handleMouseEnter = useCallback(() => { + const handleMouseEnter = () => { const {id, name} = node; hoverFiber({id, name}); - }, [node]); + }; const handleMouseLeave = () => { hoverFiber(null);