From 67b71a919008141f03533e03f207611d4fbb5a1d Mon Sep 17 00:00:00 2001 From: moklick Date: Tue, 22 Feb 2022 17:49:10 +0100 Subject: [PATCH] fix(selection-change): only trigger once --- src/components/SelectionListener/index.tsx | 27 ++++++++++++++-------- src/types/general.ts | 2 +- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/components/SelectionListener/index.tsx b/src/components/SelectionListener/index.tsx index dcd05e7d..6f052a3a 100644 --- a/src/components/SelectionListener/index.tsx +++ b/src/components/SelectionListener/index.tsx @@ -1,29 +1,38 @@ -import { useEffect } from 'react'; +import { memo, useEffect } from 'react'; import shallow from 'zustand/shallow'; -import { ReactFlowState, OnSelectionChangeFunc } from '../../types'; +import { ReactFlowState, OnSelectionChangeFunc, Node, Edge } from '../../types'; import { useStore } from '../../store'; interface SelectionListenerProps { onSelectionChange: OnSelectionChangeFunc; } -// @TODO: work with nodeInternals instead of converting it to an array const selector = (s: ReactFlowState) => ({ - selectedNodes: Array.from(s.nodeInternals) - .filter(([_, n]) => n.selected) - .map(([_, node]) => node), + selectedNodes: Array.from(s.nodeInternals.values()).filter((n) => n.selected), selectedEdges: s.edges.filter((e) => e.selected), }); +const areEqual = (objA: any, objB: any) => { + const selectedNodeIdsA = objA.selectedNodes.map((n: Node) => n.id); + const selectedNodeIdsB = objB.selectedNodes.map((n: Node) => n.id); + + const selectedEdgeIdsA = objA.selectedEdges.map((e: Edge) => e.id); + const selectedEdgeIdsB = objB.selectedEdges.map((e: Edge) => e.id); + + return shallow(selectedNodeIdsA, selectedNodeIdsB) && shallow(selectedEdgeIdsA, selectedEdgeIdsB); +}; + // This is just a helper component for calling the onSelectionChange listener. // @TODO: Now that we have the onNodesChange and on EdgesChange listeners, do we still need this component? -export default ({ onSelectionChange }: SelectionListenerProps) => { - const { selectedNodes, selectedEdges } = useStore(selector, shallow); +function SelectionListener({ onSelectionChange }: SelectionListenerProps) { + const { selectedNodes, selectedEdges } = useStore(selector, areEqual); useEffect(() => { onSelectionChange({ nodes: selectedNodes, edges: selectedEdges }); }, [selectedNodes, selectedEdges]); return null; -}; +} + +export default memo(SelectionListener); diff --git a/src/types/general.ts b/src/types/general.ts index db3a5c9d..89d4a8c2 100644 --- a/src/types/general.ts +++ b/src/types/general.ts @@ -22,7 +22,7 @@ export type OnEdgesChange = (nodes: EdgeChange[]) => void; export type OnNodesDelete = (nodes: Node[]) => void; export type OnEdgesDelete = (edges: Edge[]) => void; -export type OnMove = (event: MouseEvent | TouchEvent, viweport: Viewport) => void; +export type OnMove = (event: MouseEvent | TouchEvent, viewport: Viewport) => void; export type OnMoveStart = OnMove; export type OnMoveEnd = OnMove;