From 4f97ec539f67b4fb4bf3a74f01cbb663c78dd90c Mon Sep 17 00:00:00 2001 From: moklick Date: Tue, 17 May 2022 14:43:12 +0200 Subject: [PATCH] refactor(wrapEdge): remove unnecessary memoization --- example/src/Edges/index.tsx | 11 +- src/components/Edges/utils.ts | 18 ++- src/components/Edges/wrapEdge.tsx | 212 +++++++++++------------------- 3 files changed, 101 insertions(+), 140 deletions(-) diff --git a/example/src/Edges/index.tsx b/example/src/Edges/index.tsx index 35d6aaa4..48405154 100644 --- a/example/src/Edges/index.tsx +++ b/example/src/Edges/index.tsx @@ -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} > diff --git a/src/components/Edges/utils.ts b/src/components/Edges/utils.ts index eb4f5127..82ac7d7c 100644 --- a/src/components/Edges/utils.ts +++ b/src/components/Edges/utils.ts @@ -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, + handler?: (event: ReactMouseEvent, edge: Edge) => void +) { + return handler === undefined + ? handler + : (event: ReactMouseEvent) => { + const edge = getState().edges.find((e) => e.id === id)!; + handler(event, { ...edge }); + }; +} diff --git a/src/components/Edges/wrapEdge.tsx b/src/components/Edges/wrapEdge.tsx index 47fb9c85..7f2a66b9 100644 --- a/src/components/Edges/wrapEdge.tsx +++ b/src/components/Edges/wrapEdge.tsx @@ -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) => { markerEnd, markerStart, }: WrapEdgeProps): JSX.Element | null => { - const store = useStoreApi(); - const { addSelectedEdges, connectionMode } = useStore(selector, shallow); - const [updating, setUpdating] = useState(false); + const { addSelectedEdges, connectionMode } = useStore(selector, shallow); + const store = useStoreApi(); + + const onEdgeClick = (event: React.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, 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): void => + handleEdgeUpdater(event, true); + const onEdgeUpdaterTargetMouseDown = (event: React.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) => { { selected, animated, inactive, updating }, ]); - const edgeElement = useMemo(() => { - 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): void => { - if (elementsSelectable) { - store.setState({ nodesSelectionActive: false }); - addSelectedEdges([edgeElement.id]); - } - - onClick?.(event, edgeElement); - }, - [elementsSelectable, edgeElement, onClick] - ); - - const onEdgeDoubleClickHandler = useCallback( - (event: React.MouseEvent) => { - onEdgeDoubleClick?.(event, edgeElement); - }, - [edgeElement, onEdgeDoubleClick] - ); - - const onEdgeContextMenu = useCallback( - (event: React.MouseEvent): void => { - onContextMenu?.(event, edgeElement); - }, - [edgeElement, onContextMenu] - ); - - const onEdgeMouseEnter = useCallback( - (event: React.MouseEvent): void => { - onMouseEnter?.(event, edgeElement); - }, - [edgeElement, onContextMenu] - ); - - const onEdgeMouseMove = useCallback( - (event: React.MouseEvent): void => { - onMouseMove?.(event, edgeElement); - }, - [edgeElement, onContextMenu] - ); - - const onEdgeMouseLeave = useCallback( - (event: React.MouseEvent): void => { - onMouseLeave?.(event, edgeElement); - }, - [edgeElement, onContextMenu] - ); - - const handleEdgeUpdater = useCallback( - (event: React.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): void => { - handleEdgeUpdater(event, true); - }, - [id, source, sourceHandleId, handleEdgeUpdater] - ); - - const onEdgeUpdaterTargetMouseDown = useCallback( - (event: React.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 (