Files
flipper/desktop/plugins/public/ui-debugger/components/main.tsx
Luke De Feo 8581aa1944 Memoise selection of nodes
Summary:
For the visualiser we use the same trick as with the hover state. We subscribe to selection changes and only render if the prev or new state concerns us.

For the tree we change from object identity to the node id + and indent guide are added to the memoisation equal check.

Depending on teh change this tree memoisation can vary in effectiveness. If you go from nothing selecting to selecting the top element nothing is memoised since react needs to render every element to draw the indent guide. If you have somethign selected and select a nearby element the memoisation works well.

There are ways to improve this more down the road

changelog: UIDebugger improve performance of selecting nodes

Reviewed By: lblasa

Differential Revision: D43305979

fbshipit-source-id: 5d90e806ed7b6a8401e9968be398d4a67ed0c294
2023-02-17 02:45:05 -08:00

102 lines
3.0 KiB
TypeScript

/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
import React, {useState} from 'react';
import {plugin} from '../index';
import {
DetailSidebar,
Layout,
usePlugin,
useValue,
_Sidebar as ResizablePanel,
} from 'flipper-plugin';
import {useHotkeys} from 'react-hotkeys-hook';
import {Id, Metadata, MetadataId, UINode} from '../types';
import {PerfStats} from './PerfStats';
import {Visualization2D} from './Visualization2D';
import {useKeyboardModifiers} from '../hooks/useKeyboardModifiers';
import {Inspector} from './sidebar/Inspector';
import {Controls} from './Controls';
import {Spin} from 'antd';
import {QueryClientProvider} from 'react-query';
import FeedbackRequest from './fb-stubs/feedback';
import {Tree2} from './Tree';
export function Component() {
const instance = usePlugin(plugin);
const rootId = useValue(instance.rootId);
const nodes: Map<Id, UINode> = useValue(instance.nodes);
const metadata: Map<MetadataId, Metadata> = useValue(instance.metadata);
const [showPerfStats, setShowPerfStats] = useState(false);
const [visualiserWidth, setVisualiserWidth] = useState(500);
useHotkeys('ctrl+i', () => setShowPerfStats((show) => !show));
const {ctrlPressed} = useKeyboardModifiers();
if (showPerfStats) return <PerfStats events={instance.perfEvents} />;
if (rootId) {
return (
<QueryClientProvider client={instance.queryClient}>
<Layout.Container grow padh="small" padv="medium">
{instance.device === 'iOS' ? <FeedbackRequest /> : null}
<Controls />
<Layout.Horizontal grow pad="small" gap="small">
<Layout.Container grow gap="small">
<Layout.ScrollContainer>
<Tree2 nodes={nodes} rootId={rootId} />
</Layout.ScrollContainer>
</Layout.Container>
<ResizablePanel
position="right"
minWidth={200}
width={visualiserWidth}
maxWidth={800}
onResize={(width) => {
setVisualiserWidth(width);
}}
gutter>
<Visualization2D
rootId={rootId}
width={visualiserWidth}
nodes={nodes}
onSelectNode={instance.uiActions.onSelectNode}
modifierPressed={ctrlPressed}
/>
</ResizablePanel>
<DetailSidebar width={350}>
<Inspector metadata={metadata} nodes={nodes} />
</DetailSidebar>
</Layout.Horizontal>
</Layout.Container>
</QueryClientProvider>
);
}
return (
<Centered>
<Spin data-testid="loading-indicator" />
</Centered>
);
}
export function Centered(props: {children: React.ReactNode}) {
return (
<Layout.Horizontal center grow>
<Layout.Container center grow>
{props.children}
</Layout.Container>
</Layout.Horizontal>
);
}