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
This commit is contained in:
committed by
Facebook GitHub Bot
parent
2bdb068531
commit
a2ce6d5aac
@@ -8,7 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {Id, UINode} from '../types';
|
import {Id, UINode} from '../types';
|
||||||
import React from 'react';
|
import React, {useEffect, useState} from 'react';
|
||||||
import {
|
import {
|
||||||
HighlightManager,
|
HighlightManager,
|
||||||
HighlightProvider,
|
HighlightProvider,
|
||||||
@@ -20,6 +20,7 @@ import {
|
|||||||
} from 'flipper-plugin';
|
} from 'flipper-plugin';
|
||||||
import {plugin} from '../index';
|
import {plugin} from '../index';
|
||||||
import {Glyph} from 'flipper';
|
import {Glyph} from 'flipper';
|
||||||
|
import {head} from 'lodash';
|
||||||
|
|
||||||
export function Tree2({
|
export function Tree2({
|
||||||
nodes,
|
nodes,
|
||||||
@@ -42,7 +43,10 @@ export function Tree2({
|
|||||||
<HighlightProvider
|
<HighlightProvider
|
||||||
text={searchTerm}
|
text={searchTerm}
|
||||||
highlightColor={theme.searchHighlightBackground.yellow}>
|
highlightColor={theme.searchHighlightBackground.yellow}>
|
||||||
<div>
|
<div
|
||||||
|
onMouseLeave={() => {
|
||||||
|
instance.uiState.hoveredNodes.set([]);
|
||||||
|
}}>
|
||||||
{items.map((treeNode) => (
|
{items.map((treeNode) => (
|
||||||
<TreeItemContainer
|
<TreeItemContainer
|
||||||
key={treeNode.id}
|
key={treeNode.id}
|
||||||
@@ -64,7 +68,6 @@ export type TreeNode = UINode & {
|
|||||||
function TreeItemContainer({
|
function TreeItemContainer({
|
||||||
treeNode,
|
treeNode,
|
||||||
selectedNode,
|
selectedNode,
|
||||||
hoveredNode,
|
|
||||||
onSelectNode,
|
onSelectNode,
|
||||||
}: {
|
}: {
|
||||||
treeNode: TreeNode;
|
treeNode: TreeNode;
|
||||||
@@ -73,10 +76,14 @@ function TreeItemContainer({
|
|||||||
onSelectNode: (node?: Id) => void;
|
onSelectNode: (node?: Id) => void;
|
||||||
}) {
|
}) {
|
||||||
const instance = usePlugin(plugin);
|
const instance = usePlugin(plugin);
|
||||||
|
const isHovered = useIsHovered(treeNode.id);
|
||||||
return (
|
return (
|
||||||
<TreeItem
|
<TreeItem
|
||||||
isSelected={treeNode.id === selectedNode}
|
isSelected={treeNode.id === selectedNode}
|
||||||
isHovered={treeNode.id === hoveredNode}
|
isHovered={isHovered}
|
||||||
|
onMouseEnter={() => {
|
||||||
|
instance.uiState.hoveredNodes.set([treeNode.id]);
|
||||||
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
onSelectNode(treeNode.id);
|
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<{
|
const TreeItem = styled.li<{
|
||||||
item: TreeNode;
|
item: TreeNode;
|
||||||
isHovered: boolean;
|
isHovered: boolean;
|
||||||
|
|||||||
Reference in New Issue
Block a user