refactor(wrapEdge): remove unnecessary memoization

This commit is contained in:
moklick
2022-05-17 14:43:12 +02:00
parent 32d30e9f6b
commit 4f97ec539f
3 changed files with 101 additions and 140 deletions
+10 -1
View File
@@ -9,7 +9,6 @@ import ReactFlow, {
MarkerType, MarkerType,
MiniMap, MiniMap,
Node, Node,
Position,
ReactFlowInstance, ReactFlowInstance,
useEdgesState, useEdgesState,
useNodesState, useNodesState,
@@ -20,6 +19,11 @@ import CustomEdge2 from './CustomEdge2';
const onInit = (reactFlowInstance: ReactFlowInstance) => reactFlowInstance.fitView(); const onInit = (reactFlowInstance: ReactFlowInstance) => reactFlowInstance.fitView();
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node); const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node); const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node);
const onEdgeClick = (_: MouseEvent, edge: Edge) => console.log('click', edge);
const onEdgeDoubleClick = (_: MouseEvent, edge: Edge) => console.log('dblclick', edge);
const onEdgeMouseEnter = (_: MouseEvent, edge: Edge) => console.log('enter', edge);
const onEdgeMouseMove = (_: MouseEvent, edge: Edge) => console.log('move', edge);
const onEdgeMouseLeave = (_: MouseEvent, edge: Edge) => console.log('leave', edge);
const initialNodes: Node[] = [ const initialNodes: Node[] = [
{ id: '1', type: 'input', data: { label: 'Input 1' }, position: { x: 250, y: 0 } }, { id: '1', type: 'input', data: { label: 'Input 1' }, position: { x: 250, y: 0 } },
@@ -131,6 +135,11 @@ const EdgesFlow = () => {
onInit={onInit} onInit={onInit}
snapToGrid={true} snapToGrid={true}
edgeTypes={edgeTypes} edgeTypes={edgeTypes}
onEdgeClick={onEdgeClick}
onEdgeDoubleClick={onEdgeDoubleClick}
onEdgeMouseEnter={onEdgeMouseEnter}
onEdgeMouseMove={onEdgeMouseMove}
onEdgeMouseLeave={onEdgeMouseLeave}
> >
<MiniMap /> <MiniMap />
<Controls /> <Controls />
+17 -1
View File
@@ -1,4 +1,7 @@
import { MarkerType, Position } from '../../types'; import { MouseEvent as ReactMouseEvent } from 'react';
import { GetState } from 'zustand';
import { Edge, MarkerType, Position, ReactFlowState } from '../../types';
export const getMarkerEnd = (markerType?: MarkerType, markerEndId?: string): string => { export const getMarkerEnd = (markerType?: MarkerType, markerEndId?: string): string => {
if (typeof markerEndId !== 'undefined' && markerEndId) { if (typeof markerEndId !== 'undefined' && markerEndId) {
@@ -52,3 +55,16 @@ export const getCenter = ({
return [centerX, centerY, xOffset, yOffset]; return [centerX, centerY, xOffset, yOffset];
}; };
export function getMouseHandler(
id: string,
getState: GetState<ReactFlowState>,
handler?: (event: ReactMouseEvent<SVGGElement, MouseEvent>, edge: Edge) => void
) {
return handler === undefined
? handler
: (event: ReactMouseEvent<SVGGElement, MouseEvent>) => {
const edge = getState().edges.find((e) => e.id === id)!;
handler(event, { ...edge });
};
}
+33 -97
View File
@@ -1,12 +1,13 @@
import React, { memo, ComponentType, useCallback, useState, useMemo } from 'react'; import React, { memo, ComponentType, useState, useMemo } from 'react';
import cc from 'classcat'; import cc from 'classcat';
import shallow from 'zustand/shallow'; import shallow from 'zustand/shallow';
import { useStore, useStoreApi } from '../../store'; import { useStore, useStoreApi } from '../../store';
import { Edge, EdgeProps, WrapEdgeProps, ReactFlowState, Connection } from '../../types'; import { EdgeProps, WrapEdgeProps, ReactFlowState, Connection } from '../../types';
import { handleMouseDown } from '../../components/Handle/handler'; import { handleMouseDown } from '../../components/Handle/handler';
import { EdgeAnchor } from './EdgeAnchor'; import { EdgeAnchor } from './EdgeAnchor';
import { getMarkerId } from '../../utils/graph'; import { getMarkerId } from '../../utils/graph';
import { getMouseHandler } from './utils';
const selector = (s: ReactFlowState) => ({ const selector = (s: ReactFlowState) => ({
addSelectedEdges: s.addSelectedEdges, addSelectedEdges: s.addSelectedEdges,
@@ -53,102 +54,39 @@ export default (EdgeComponent: ComponentType<EdgeProps>) => {
markerEnd, markerEnd,
markerStart, markerStart,
}: WrapEdgeProps): JSX.Element | null => { }: WrapEdgeProps): JSX.Element | null => {
const store = useStoreApi();
const { addSelectedEdges, connectionMode } = useStore(selector, shallow);
const [updating, setUpdating] = useState<boolean>(false); const [updating, setUpdating] = useState<boolean>(false);
const { addSelectedEdges, connectionMode } = useStore(selector, shallow);
const store = useStoreApi();
const inactive = !elementsSelectable && !onClick; const onEdgeClick = (event: React.MouseEvent<SVGGElement, MouseEvent>): void => {
const handleEdgeUpdate = typeof onEdgeUpdate !== 'undefined'; const edge = store.getState().edges.find((e) => e.id === id)!;
const edgeClasses = cc([
'react-flow__edge',
`react-flow__edge-${type}`,
className,
{ selected, animated, inactive, updating },
]);
const edgeElement = useMemo<Edge>(() => {
const el: Edge = {
id,
source,
target,
type,
};
if (sourceHandleId) {
el.sourceHandle = sourceHandleId;
}
if (targetHandleId) {
el.targetHandle = targetHandleId;
}
if (typeof data !== 'undefined') {
el.data = data;
}
return el;
}, [id, source, target, type, sourceHandleId, targetHandleId, data]);
const onEdgeClick = useCallback(
(event: React.MouseEvent<SVGGElement, MouseEvent>): void => {
if (elementsSelectable) { if (elementsSelectable) {
store.setState({ nodesSelectionActive: false }); store.setState({ nodesSelectionActive: false });
addSelectedEdges([edgeElement.id]); addSelectedEdges([id]);
} }
onClick?.(event, edgeElement); onClick?.(event, edge);
}, };
[elementsSelectable, edgeElement, onClick]
);
const onEdgeDoubleClickHandler = useCallback( const onEdgeDoubleClickHandler = getMouseHandler(id, store.getState, onEdgeDoubleClick);
(event: React.MouseEvent<SVGGElement, MouseEvent>) => { const onEdgeContextMenu = getMouseHandler(id, store.getState, onContextMenu);
onEdgeDoubleClick?.(event, edgeElement); const onEdgeMouseEnter = getMouseHandler(id, store.getState, onMouseEnter);
}, const onEdgeMouseMove = getMouseHandler(id, store.getState, onMouseMove);
[edgeElement, onEdgeDoubleClick] const onEdgeMouseLeave = getMouseHandler(id, store.getState, onMouseLeave);
);
const onEdgeContextMenu = useCallback( const handleEdgeUpdater = (event: React.MouseEvent<SVGGElement, MouseEvent>, isSourceHandle: boolean) => {
(event: React.MouseEvent<SVGGElement, MouseEvent>): void => {
onContextMenu?.(event, edgeElement);
},
[edgeElement, onContextMenu]
);
const onEdgeMouseEnter = useCallback(
(event: React.MouseEvent<SVGGElement, MouseEvent>): void => {
onMouseEnter?.(event, edgeElement);
},
[edgeElement, onContextMenu]
);
const onEdgeMouseMove = useCallback(
(event: React.MouseEvent<SVGGElement, MouseEvent>): void => {
onMouseMove?.(event, edgeElement);
},
[edgeElement, onContextMenu]
);
const onEdgeMouseLeave = useCallback(
(event: React.MouseEvent<SVGGElement, MouseEvent>): void => {
onMouseLeave?.(event, edgeElement);
},
[edgeElement, onContextMenu]
);
const handleEdgeUpdater = useCallback(
(event: React.MouseEvent<SVGGElement, MouseEvent>, isSourceHandle: boolean) => {
const nodeId = isSourceHandle ? target : source; const nodeId = isSourceHandle ? target : source;
const handleId = (isSourceHandle ? targetHandleId : sourceHandleId) || null; const handleId = (isSourceHandle ? targetHandleId : sourceHandleId) || null;
const handleType = isSourceHandle ? 'target' : 'source'; const handleType = isSourceHandle ? 'target' : 'source';
const isValidConnection = () => true; const isValidConnection = () => true;
const isTarget = isSourceHandle; const isTarget = isSourceHandle;
const edge = store.getState().edges.find((e) => e.id === id)!;
onEdgeUpdateStart?.(event, edgeElement, handleType); onEdgeUpdateStart?.(event, edge, handleType);
const _onEdgeUpdate = onEdgeUpdateEnd const _onEdgeUpdate = onEdgeUpdateEnd
? (evt: MouseEvent): void => onEdgeUpdateEnd(evt, edgeElement, handleType) ? (evt: MouseEvent): void => onEdgeUpdateEnd(evt, edge, handleType)
: undefined; : undefined;
const onConnectEdge = (connection: Connection) => { const onConnectEdge = (connection: Connection) => {
@@ -173,26 +111,15 @@ export default (EdgeComponent: ComponentType<EdgeProps>) => {
_onEdgeUpdate, _onEdgeUpdate,
store.getState store.getState
); );
}, };
[id, source, target, type, sourceHandleId, targetHandleId, edgeElement, onEdgeUpdate]
);
const onEdgeUpdaterSourceMouseDown = useCallback( const onEdgeUpdaterSourceMouseDown = (event: React.MouseEvent<SVGGElement, MouseEvent>): void =>
(event: React.MouseEvent<SVGGElement, MouseEvent>): void => {
handleEdgeUpdater(event, true); handleEdgeUpdater(event, true);
}, const onEdgeUpdaterTargetMouseDown = (event: React.MouseEvent<SVGGElement, MouseEvent>): void =>
[id, source, sourceHandleId, handleEdgeUpdater]
);
const onEdgeUpdaterTargetMouseDown = useCallback(
(event: React.MouseEvent<SVGGElement, MouseEvent>): void => {
handleEdgeUpdater(event, false); handleEdgeUpdater(event, false);
},
[id, target, targetHandleId, handleEdgeUpdater]
);
const onEdgeUpdaterMouseEnter = useCallback(() => setUpdating(true), [setUpdating]); const onEdgeUpdaterMouseEnter = () => setUpdating(true);
const onEdgeUpdaterMouseOut = useCallback(() => setUpdating(false), [setUpdating]); const onEdgeUpdaterMouseOut = () => setUpdating(false);
const markerStartUrl = useMemo(() => `url(#${getMarkerId(markerStart)})`, [markerStart]); const markerStartUrl = useMemo(() => `url(#${getMarkerId(markerStart)})`, [markerStart]);
const markerEndUrl = useMemo(() => `url(#${getMarkerId(markerEnd)})`, [markerEnd]); const markerEndUrl = useMemo(() => `url(#${getMarkerId(markerEnd)})`, [markerEnd]);
@@ -200,6 +127,15 @@ export default (EdgeComponent: ComponentType<EdgeProps>) => {
return null; return null;
} }
const inactive = !elementsSelectable && !onClick;
const handleEdgeUpdate = typeof onEdgeUpdate !== 'undefined';
const edgeClasses = cc([
'react-flow__edge',
`react-flow__edge-${type}`,
className,
{ selected, animated, inactive, updating },
]);
return ( return (
<g <g
className={edgeClasses} className={edgeClasses}