diff --git a/.changeset/shy-kings-compare.md b/.changeset/shy-kings-compare.md new file mode 100644 index 00000000..eae6df6b --- /dev/null +++ b/.changeset/shy-kings-compare.md @@ -0,0 +1,5 @@ +--- +"@vue-flow/core": minor +--- + +Replace internally nodeIds/edgeIds array with nodeLookup/edgeLookup map diff --git a/packages/core/src/store/actions.ts b/packages/core/src/store/actions.ts index 20f1ddff..ce090e76 100644 --- a/packages/core/src/store/actions.ts +++ b/packages/core/src/store/actions.ts @@ -8,6 +8,7 @@ import type { Edge, EdgeAddChange, EdgeChange, + EdgeLookup, EdgeRemoveChange, EdgeSelectionChange, Elements, @@ -18,6 +19,7 @@ import type { NodeAddChange, NodeChange, NodeDimensionChange, + NodeLookup, NodePositionChange, NodeRemoveChange, NodeSelectionChange, @@ -55,15 +57,13 @@ import { storeOptionsToSkip, useState } from './state' export function useActions( id: string, state: State, - // todo: change to a Set - nodeIds: ComputedRef, - // todo: change to a Set - edgeIds: ComputedRef, + nodeLookup: ComputedRef, + edgeLookup: ComputedRef, ): Actions { const viewportHelper = useViewportHelper(state) const updateNodeInternals: Actions['updateNodeInternals'] = (ids) => { - const updateIds = ids ?? nodeIds.value ?? [] + const updateIds = ids ?? state.nodes.map((n) => n.id) ?? [] state.hooks.updateNodeInternals.trigger(updateIds) } @@ -85,11 +85,7 @@ export function useActions( return } - if (state.nodes && !nodeIds.value.length) { - return state.nodes.find((node) => node.id === id) - } - - return state.nodes[nodeIds.value.indexOf(id)] + return nodeLookup.value.get(id) } const findEdge: Actions['findEdge'] = (id) => { @@ -97,11 +93,7 @@ export function useActions( return } - if (state.edges && !edgeIds.value.length) { - return state.edges.find((edge) => edge.id === id) - } - - return state.edges[edgeIds.value.indexOf(id)] + return edgeLookup.value.get(id) } const updateNodePositions: Actions['updateNodePositions'] = (dragItems, changed, dragging) => { @@ -370,7 +362,7 @@ export function useActions( const setNodeExtent: Actions['setNodeExtent'] = (nodeExtent) => { state.nodeExtent = nodeExtent - updateNodeInternals(nodeIds.value) + updateNodeInternals() } const setInteractive: Actions['setInteractive'] = (isInteractive) => { diff --git a/packages/core/src/store/getters.ts b/packages/core/src/store/getters.ts index fc11d7e1..f021b448 100644 --- a/packages/core/src/store/getters.ts +++ b/packages/core/src/store/getters.ts @@ -1,31 +1,23 @@ import type { ComputedRef } from 'vue' import { computed } from 'vue' -import type { ComputedGetters, GraphEdge, GraphNode, State } from '../types' +import type { ComputedGetters, EdgeLookup, GraphEdge, GraphNode, NodeLookup, State } from '../types' import { getNodesInside, isEdgeVisible } from '../utils' import { defaultEdgeTypes, defaultNodeTypes } from '../utils/defaultNodesEdges' -export function useGetters(state: State, nodeIds: ComputedRef, edgeIds: ComputedRef): ComputedGetters { +export function useGetters( + state: State, + nodeLookup: ComputedRef, + edgeLookup: ComputedRef, +): ComputedGetters { /** * @deprecated will be removed in next major version; use findNode instead */ - const getNode: ComputedGetters['getNode'] = computed(() => (id: string) => { - if (state.nodes && !nodeIds.value.length) { - return state.nodes.find((node) => node.id === id) - } - - return state.nodes[nodeIds.value.indexOf(id)] - }) + const getNode: ComputedGetters['getNode'] = computed(() => (id) => nodeLookup.value.get(id)) /** * @deprecated will be removed in next major version; use findEdge instead */ - const getEdge: ComputedGetters['getEdge'] = computed(() => (id: string) => { - if (state.edges && !edgeIds.value.length) { - return state.edges.find((edge) => edge.id === id) - } - - return state.edges[edgeIds.value.indexOf(id)] - }) + const getEdge: ComputedGetters['getEdge'] = computed(() => (id) => edgeLookup.value.get(id)) const getEdgeTypes: ComputedGetters['getEdgeTypes'] = computed(() => { const edgeTypes: Record = { @@ -80,8 +72,8 @@ export function useGetters(state: State, nodeIds: ComputedRef, edgeIds const visibleEdges: GraphEdge[] = [] for (const edge of state.edges) { - const source = getNode.value(edge.source)! - const target = getNode.value(edge.target)! + const source = nodeLookup.value.get(edge.source)! + const target = nodeLookup.value.get(edge.target)! if ( isEdgeVisible({ diff --git a/packages/core/src/types/store.ts b/packages/core/src/types/store.ts index 6d4c5771..048df418 100644 --- a/packages/core/src/types/store.ts +++ b/packages/core/src/types/store.ts @@ -31,6 +31,10 @@ import type { CustomEvent, FlowHooks, FlowHooksEmit, FlowHooksOn } from './hooks import type { EdgeChange, NodeChange, NodeDragItem } from './changes' import type { ConnectingHandle, ValidConnectionFunc } from './handle' +export type NodeLookup = Map + +export type EdgeLookup = Map + export interface UpdateNodeDimensionsParams { id: string nodeElement: HTMLDivElement diff --git a/packages/core/src/utils/storage.ts b/packages/core/src/utils/storage.ts index 9895d824..51b5f54f 100644 --- a/packages/core/src/utils/storage.ts +++ b/packages/core/src/utils/storage.ts @@ -1,6 +1,6 @@ import { toRefs } from '@vueuse/core' import { computed, getCurrentInstance, reactive } from 'vue' -import type { FlowOptions, VueFlowStore } from '../types' +import type { FlowOptions, GraphEdge, GraphNode, VueFlowStore } from '../types' import { useActions, useGetters, useState } from '../store' /** @@ -57,27 +57,28 @@ export class Storage { } // for lookup purposes - const nodeIds = computed(() => { - const ids: string[] = [] + const nodeLookup = computed(() => { + const nodesMap = new Map() for (const node of reactiveState.nodes) { - ids.push(node.id) + nodesMap.set(node.id, node) } - return ids + return nodesMap }) - const edgeIds = computed(() => { - const ids: string[] = [] + const edgeLookup = computed(() => { + const edgesMap = new Map() + for (const edge of reactiveState.edges) { - ids.push(edge.id) + edgesMap.set(edge.id, edge) } - return ids + return edgesMap }) - const getters = useGetters(reactiveState, nodeIds, edgeIds) + const getters = useGetters(reactiveState, nodeLookup, edgeLookup) - const actions = useActions(id, reactiveState, nodeIds, edgeIds) + const actions = useActions(id, reactiveState, nodeLookup, edgeLookup) actions.setState({ ...reactiveState, ...preloadedState })