From a2ce6d5aacc8bcfcd2a8f3ea4bcd708a4c8dc743 Mon Sep 17 00:00:00 2001 From: Luke De Feo Date: Mon, 12 Dec 2022 07:28:37 -0800 Subject: [PATCH] Added fast hover to tree Summary: While moving mouse and changing hover state react render is under 1ms due to subscribing to state rather than passing hover as prop to all components Reviewed By: lblasa Differential Revision: D41838168 fbshipit-source-id: c9b3334adc44df5018e0a785684a2883aeb3bab1 --- .../public/ui-debugger/components/Tree2.tsx | 36 ++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/desktop/plugins/public/ui-debugger/components/Tree2.tsx b/desktop/plugins/public/ui-debugger/components/Tree2.tsx index 056ef56ff..f3064ed04 100644 --- a/desktop/plugins/public/ui-debugger/components/Tree2.tsx +++ b/desktop/plugins/public/ui-debugger/components/Tree2.tsx @@ -8,7 +8,7 @@ */ import {Id, UINode} from '../types'; -import React from 'react'; +import React, {useEffect, useState} from 'react'; import { HighlightManager, HighlightProvider, @@ -20,6 +20,7 @@ import { } from 'flipper-plugin'; import {plugin} from '../index'; import {Glyph} from 'flipper'; +import {head} from 'lodash'; export function Tree2({ nodes, @@ -42,7 +43,10 @@ export function Tree2({ -
+
{ + instance.uiState.hoveredNodes.set([]); + }}> {items.map((treeNode) => ( void; }) { const instance = usePlugin(plugin); + const isHovered = useIsHovered(treeNode.id); return ( { + instance.uiState.hoveredNodes.set([treeNode.id]); + }} onClick={() => { onSelectNode(treeNode.id); }} @@ -100,6 +107,27 @@ function TreeItemContainer({ ); } +function useIsHovered(nodeId: Id) { + const instance = usePlugin(plugin); + const [isHovered, setIsHovered] = useState(false); + useEffect(() => { + const listener = (newValue?: Id[], prevValue?: Id[]) => { + //only change state if the prev or next hover state affect us, this avoids rerendering the whole tree for a hover + //change + if (head(prevValue) === nodeId || head(newValue) === nodeId) { + const hovered = head(newValue) === nodeId; + setIsHovered(hovered); + } + }; + instance.uiState.hoveredNodes.subscribe(listener); + return () => { + instance.uiState.hoveredNodes.unsubscribe(listener); + }; + }, [instance.uiState.hoveredNodes, nodeId]); + + return isHovered; +} + const TreeItem = styled.li<{ item: TreeNode; isHovered: boolean;