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

View File

@@ -9,7 +9,6 @@ import ReactFlow, {
MarkerType,
MiniMap,
Node,
Position,
ReactFlowInstance,
useEdgesState,
useNodesState,
@@ -20,6 +19,11 @@ import CustomEdge2 from './CustomEdge2';
const onInit = (reactFlowInstance: ReactFlowInstance) => reactFlowInstance.fitView();
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', 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[] = [
{ id: '1', type: 'input', data: { label: 'Input 1' }, position: { x: 250, y: 0 } },
@@ -131,6 +135,11 @@ const EdgesFlow = () => {
onInit={onInit}
snapToGrid={true}
edgeTypes={edgeTypes}
onEdgeClick={onEdgeClick}
onEdgeDoubleClick={onEdgeDoubleClick}
onEdgeMouseEnter={onEdgeMouseEnter}
onEdgeMouseMove={onEdgeMouseMove}
onEdgeMouseLeave={onEdgeMouseLeave}
>
<MiniMap />
<Controls />

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 => {
if (typeof markerEndId !== 'undefined' && markerEndId) {
@@ -52,3 +55,16 @@ export const getCenter = ({
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 });
};
}

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 shallow from 'zustand/shallow';
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 { EdgeAnchor } from './EdgeAnchor';
import { getMarkerId } from '../../utils/graph';
import { getMouseHandler } from './utils';
const selector = (s: ReactFlowState) => ({
addSelectedEdges: s.addSelectedEdges,
@@ -53,10 +54,78 @@ export default (EdgeComponent: ComponentType<EdgeProps>) => {
markerEnd,
markerStart,
}: WrapEdgeProps): JSX.Element | null => {
const store = useStoreApi();
const { addSelectedEdges, connectionMode } = useStore(selector, shallow);
const [updating, setUpdating] = useState<boolean>(false);
const { addSelectedEdges, connectionMode } = useStore(selector, shallow);
const store = useStoreApi();
const onEdgeClick = (event: React.MouseEvent<SVGGElement, MouseEvent>): void => {
const edge = store.getState().edges.find((e) => e.id === id)!;
if (elementsSelectable) {
store.setState({ nodesSelectionActive: false });
addSelectedEdges([id]);
}
onClick?.(event, edge);
};
const onEdgeDoubleClickHandler = getMouseHandler(id, store.getState, onEdgeDoubleClick);
const onEdgeContextMenu = getMouseHandler(id, store.getState, onContextMenu);
const onEdgeMouseEnter = getMouseHandler(id, store.getState, onMouseEnter);
const onEdgeMouseMove = getMouseHandler(id, store.getState, onMouseMove);
const onEdgeMouseLeave = getMouseHandler(id, store.getState, onMouseLeave);
const handleEdgeUpdater = (event: React.MouseEvent<SVGGElement, MouseEvent>, isSourceHandle: boolean) => {
const nodeId = isSourceHandle ? target : source;
const handleId = (isSourceHandle ? targetHandleId : sourceHandleId) || null;
const handleType = isSourceHandle ? 'target' : 'source';
const isValidConnection = () => true;
const isTarget = isSourceHandle;
const edge = store.getState().edges.find((e) => e.id === id)!;
onEdgeUpdateStart?.(event, edge, handleType);
const _onEdgeUpdate = onEdgeUpdateEnd
? (evt: MouseEvent): void => onEdgeUpdateEnd(evt, edge, handleType)
: undefined;
const onConnectEdge = (connection: Connection) => {
const { edges } = store.getState();
const edge = edges.find((e) => e.id === id);
if (edge && onEdgeUpdate) {
onEdgeUpdate(edge, connection);
}
};
handleMouseDown(
event,
handleId,
nodeId,
store.setState,
onConnectEdge,
isTarget,
isValidConnection,
connectionMode,
handleType,
_onEdgeUpdate,
store.getState
);
};
const onEdgeUpdaterSourceMouseDown = (event: React.MouseEvent<SVGGElement, MouseEvent>): void =>
handleEdgeUpdater(event, true);
const onEdgeUpdaterTargetMouseDown = (event: React.MouseEvent<SVGGElement, MouseEvent>): void =>
handleEdgeUpdater(event, false);
const onEdgeUpdaterMouseEnter = () => setUpdating(true);
const onEdgeUpdaterMouseOut = () => setUpdating(false);
const markerStartUrl = useMemo(() => `url(#${getMarkerId(markerStart)})`, [markerStart]);
const markerEndUrl = useMemo(() => `url(#${getMarkerId(markerEnd)})`, [markerEnd]);
if (hidden) {
return null;
}
const inactive = !elementsSelectable && !onClick;
const handleEdgeUpdate = typeof onEdgeUpdate !== 'undefined';
@@ -67,139 +136,6 @@ export default (EdgeComponent: ComponentType<EdgeProps>) => {
{ 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) {
store.setState({ nodesSelectionActive: false });
addSelectedEdges([edgeElement.id]);
}
onClick?.(event, edgeElement);
},
[elementsSelectable, edgeElement, onClick]
);
const onEdgeDoubleClickHandler = useCallback(
(event: React.MouseEvent<SVGGElement, MouseEvent>) => {
onEdgeDoubleClick?.(event, edgeElement);
},
[edgeElement, onEdgeDoubleClick]
);
const onEdgeContextMenu = useCallback(
(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 handleId = (isSourceHandle ? targetHandleId : sourceHandleId) || null;
const handleType = isSourceHandle ? 'target' : 'source';
const isValidConnection = () => true;
const isTarget = isSourceHandle;
onEdgeUpdateStart?.(event, edgeElement, handleType);
const _onEdgeUpdate = onEdgeUpdateEnd
? (evt: MouseEvent): void => onEdgeUpdateEnd(evt, edgeElement, handleType)
: undefined;
const onConnectEdge = (connection: Connection) => {
const { edges } = store.getState();
const edge = edges.find((e) => e.id === id);
if (edge && onEdgeUpdate) {
onEdgeUpdate(edge, connection);
}
};
handleMouseDown(
event,
handleId,
nodeId,
store.setState,
onConnectEdge,
isTarget,
isValidConnection,
connectionMode,
handleType,
_onEdgeUpdate,
store.getState
);
},
[id, source, target, type, sourceHandleId, targetHandleId, edgeElement, onEdgeUpdate]
);
const onEdgeUpdaterSourceMouseDown = useCallback(
(event: React.MouseEvent<SVGGElement, MouseEvent>): void => {
handleEdgeUpdater(event, true);
},
[id, source, sourceHandleId, handleEdgeUpdater]
);
const onEdgeUpdaterTargetMouseDown = useCallback(
(event: React.MouseEvent<SVGGElement, MouseEvent>): void => {
handleEdgeUpdater(event, false);
},
[id, target, targetHandleId, handleEdgeUpdater]
);
const onEdgeUpdaterMouseEnter = useCallback(() => setUpdating(true), [setUpdating]);
const onEdgeUpdaterMouseOut = useCallback(() => setUpdating(false), [setUpdating]);
const markerStartUrl = useMemo(() => `url(#${getMarkerId(markerStart)})`, [markerStart]);
const markerEndUrl = useMemo(() => `url(#${getMarkerId(markerEnd)})`, [markerEnd]);
if (hidden) {
return null;
}
return (
<g
className={edgeClasses}