diff --git a/examples/react/src/examples/Stress/index.tsx b/examples/react/src/examples/Stress/index.tsx index 9020ddd6..496fd500 100644 --- a/examples/react/src/examples/Stress/index.tsx +++ b/examples/react/src/examples/Stress/index.tsx @@ -12,6 +12,8 @@ import { Controls, Background, Panel, + ReactFlowProvider, + useReactFlow, } from '@xyflow/react'; import { getNodesAndEdges } from './utils'; @@ -22,6 +24,7 @@ const { nodes: initialNodes, edges: initialEdges } = getNodesAndEdges(25, 25); const StressFlow = () => { const [nodes, setNodes] = useState(initialNodes); const [edges, setEdges] = useState(initialEdges); + const { fitView } = useReactFlow(); const onConnect = useCallback((connection: Connection) => { setEdges((eds) => addEdge(connection, eds)); }, []); @@ -191,12 +194,13 @@ const StressFlow = () => { return { ...n, position: { - x: Math.random() * window.innerWidth, - y: Math.random() * window.innerHeight, + x: Math.random() * window.innerWidth * 4, + y: Math.random() * window.innerHeight * 4, }, }; }); }); + fitView(); }; const updateElements = () => { @@ -240,4 +244,10 @@ const StressFlow = () => { ); }; -export default StressFlow; +export default function StressFlowProvider() { + return ( + + + + ); +} diff --git a/packages/react/src/store/index.ts b/packages/react/src/store/index.ts index 909d8572..8b219d27 100644 --- a/packages/react/src/store/index.ts +++ b/packages/react/src/store/index.ts @@ -41,11 +41,36 @@ const createStore = ({ nodeOrigin?: NodeOrigin; nodeExtent?: CoordinateExtent; }) => - createWithEqualityFn( - (set, get) => ({ + createWithEqualityFn((set, get) => { + function resolveFitView() { + const { nodeLookup, panZoom, fitViewOptions, fitViewResolver, width, height, minZoom, maxZoom } = get(); + + if (!panZoom) { + return; + } + + const fitViewPromise = fitViewport( + { + nodes: nodeLookup, + width, + height, + panZoom, + minZoom, + maxZoom, + }, + fitViewOptions + ); + fitViewPromise.then((value) => { + fitViewResolver?.resolve(value); + set({ fitViewResolver: null }); + }); + set({ nodes, fitViewQueued: false, fitViewOptions: undefined }); + } + + return { ...getInitialState({ nodes, edges, width, height, fitView, nodeOrigin, nodeExtent, defaultNodes, defaultEdges }), setNodes: (nodes: Node[]) => { - const { nodeLookup, parentLookup, nodeOrigin, elevateNodesOnSelect, fitViewQueued, panZoom } = get(); + const { nodeLookup, parentLookup, nodeOrigin, elevateNodesOnSelect, fitViewQueued } = get(); /* * setNodes() is called exclusively in response to user actions: * - either when the `` prop is updated in the controlled ReactFlow setup, @@ -62,24 +87,8 @@ const createStore = ({ checkEquality: true, }); - if (fitViewQueued && nodesInitialized && panZoom) { - const { fitViewOptions, fitViewResolver, width, height, minZoom, maxZoom } = get(); - const fitViewPromise = fitViewport( - { - nodes: nodeLookup, - width, - height, - panZoom, - minZoom, - maxZoom, - }, - fitViewOptions - ); - fitViewPromise.then((value) => { - fitViewResolver?.resolve(value); - set({ fitViewResolver: null }); - }); - set({ nodes, fitViewQueued: false, fitViewOptions: undefined }); + if (fitViewQueued && nodesInitialized) { + resolveFitView(); } else { set({ nodes }); } @@ -109,7 +118,8 @@ const createStore = ({ * new dimensions and update the nodes. */ updateNodeInternals: (updates) => { - const { triggerNodeChanges, nodeLookup, parentLookup, domNode, nodeOrigin, nodeExtent, debug } = get(); + const { triggerNodeChanges, nodeLookup, parentLookup, domNode, nodeOrigin, nodeExtent, debug, fitViewQueued } = + get(); const { changes, updatedInternals } = updateNodeInternalsSystem( updates, @@ -126,8 +136,12 @@ const createStore = ({ updateAbsolutePositions(nodeLookup, parentLookup, { nodeOrigin, nodeExtent }); - // we always want to trigger useStore calls whenever updateNodeInternals is called - set({}); + if (fitViewQueued) { + resolveFitView(); + } else { + // we always want to trigger useStore calls whenever updateNodeInternals is called + set({}); + } if (changes?.length > 0) { if (debug) { @@ -329,8 +343,7 @@ const createStore = ({ }, reset: () => set({ ...getInitialState() }), - }), - Object.is - ); + }; + }, Object.is); export { createStore }; diff --git a/packages/react/src/store/initialState.ts b/packages/react/src/store/initialState.ts index c63c9e9c..8be408b8 100644 --- a/packages/react/src/store/initialState.ts +++ b/packages/react/src/store/initialState.ts @@ -108,7 +108,7 @@ const getInitialState = ({ multiSelectionActive: false, - fitViewQueued: false, + fitViewQueued: fitView ?? false, fitViewOptions: undefined, fitViewResolver: null,