fix(react): re-measure nodes correctly

This commit is contained in:
moklick
2024-02-15 17:59:54 +01:00
parent 04ba6e0e4e
commit edba3963d8
6 changed files with 41 additions and 42 deletions
@@ -101,12 +101,12 @@ export function EdgeWrapper({
);
const markerStartUrl = useMemo(
() => (edge.markerStart ? `url(#${getMarkerId(edge.markerStart, rfId)})` : undefined),
() => (edge.markerStart ? `url('#${getMarkerId(edge.markerStart, rfId)}')` : undefined),
[edge.markerStart, rfId]
);
const markerEndUrl = useMemo(
() => (edge.markerEnd ? `url(#${getMarkerId(edge.markerEnd, rfId)})` : undefined),
() => (edge.markerEnd ? `url('#${getMarkerId(edge.markerEnd, rfId)}')` : undefined),
[edge.markerEnd, rfId]
);
@@ -84,22 +84,28 @@ export function NodeWrapper({
const computedWidth = node.computed?.width;
const computedHeight = node.computed?.height;
const initialized = (!!computedWidth && !!computedHeight) || (!!width && !!height);
const hasHandleBounds = !!node[internalsSymbol]?.handleBounds;
const moveSelectedNodes = useMoveSelectedNodes();
useEffect(() => {
return () => {
if (nodeRef.current) {
resizeObserver?.unobserve(nodeRef.current);
}
};
}, []);
useEffect(() => {
if (nodeRef.current && !node.hidden) {
const currNode = nodeRef.current;
if (!initialized) {
resizeObserver?.observe(currNode);
} else {
if (!initialized || !hasHandleBounds) {
resizeObserver?.unobserve(currNode);
resizeObserver?.observe(currNode);
}
return () => resizeObserver?.unobserve(currNode);
}
}, [node.hidden, initialized]);
}, [node.hidden, initialized, hasHandleBounds]);
useEffect(() => {
// when the user programmatically changes the source or handle position, we re-initialize the node
@@ -9,7 +9,7 @@ import { infiniteExtent, type CoordinateExtent } from '@xyflow/system';
import { useStore, useStoreApi } from '../../hooks/useStore';
import type { Node, Edge, ReactFlowState, ReactFlowProps, FitViewOptions } from '../../types';
import { initNodeOrigin } from '../../container/ReactFlow';
import { defaultNodeOrigin } from '../../container/ReactFlow/init-values';
// these fields exist in the global store and we need to keep them up to date
const reactFlowFieldsToTrack = [
@@ -84,6 +84,19 @@ const selector = (s: ReactFlowState) => ({
setDefaultNodesAndEdges: s.setDefaultNodesAndEdges,
});
const initPrevValues = {
// these are values that are also passed directly to other components
// than the StoreUpdater. We can reduce the number of setStore calls
// by setting the same values here as prev fields.
translateExtent: infiniteExtent,
nodeOrigin: defaultNodeOrigin,
minZoom: 0.5,
maxZoom: 2,
elementsSelectable: true,
noPanClassName: 'nopan',
rfId: '1',
};
export function StoreUpdater(props: StoreUpdaterProps) {
const {
setNodes,
@@ -99,23 +112,15 @@ export function StoreUpdater(props: StoreUpdaterProps) {
useEffect(() => {
setDefaultNodesAndEdges(props.defaultNodes, props.defaultEdges);
return () => {
// when we reset the store we also need to reset the previous fields
previousFields.current = initPrevValues;
reset();
};
}, []);
const previousFields = useRef<Partial<StoreUpdaterProps>>({
// these are values that are also passed directly to other components
// than the StoreUpdater. We can reduce the number of setStore calls
// by setting the same values here as prev fields.
translateExtent: infiniteExtent,
nodeOrigin: initNodeOrigin,
minZoom: 0.5,
maxZoom: 2,
elementsSelectable: true,
noPanClassName: 'nopan',
rfId: '1',
});
const previousFields = useRef<Partial<StoreUpdaterProps>>(initPrevValues);
useEffect(
() => {
@@ -1,14 +1,6 @@
import { forwardRef, type CSSProperties } from 'react';
import cc from 'classcat';
import {
ConnectionLineType,
PanOnScrollMode,
SelectionMode,
infiniteExtent,
isMacOs,
type NodeOrigin,
type Viewport,
} from '@xyflow/system';
import { ConnectionLineType, PanOnScrollMode, SelectionMode, infiniteExtent, isMacOs } from '@xyflow/system';
import { A11yDescriptions } from '../../components/A11yDescriptions';
import { Attribution } from '../../components/Attribution';
@@ -18,9 +10,7 @@ import { useColorModeClass } from '../../hooks/useColorModeClass';
import { GraphView } from '../GraphView';
import { Wrapper } from './Wrapper';
import type { ReactFlowProps, ReactFlowRefType } from '../../types';
export const initNodeOrigin: NodeOrigin = [0, 0];
const initDefaultViewport: Viewport = { x: 0, y: 0, zoom: 1 };
import { defaultViewport as initViewport, defaultNodeOrigin } from './init-values';
const wrapperStyle: CSSProperties = {
width: '100%',
@@ -89,11 +79,11 @@ const ReactFlow = forwardRef<ReactFlowRefType, ReactFlowProps>(
nodesDraggable,
nodesConnectable,
nodesFocusable,
nodeOrigin = initNodeOrigin,
nodeOrigin = defaultNodeOrigin,
edgesFocusable,
edgesUpdatable,
elementsSelectable = true,
defaultViewport = initDefaultViewport,
defaultViewport = initViewport,
minZoom = 0.5,
maxZoom = 2,
translateExtent = infiniteExtent,
@@ -0,0 +1,4 @@
import { type NodeOrigin, Viewport } from '@xyflow/system';
export const defaultNodeOrigin: NodeOrigin = [0, 0];
export const defaultViewport: Viewport = { x: 0, y: 0, zoom: 1 };
+1 -7
View File
@@ -303,13 +303,7 @@ const createRFStore = ({
set(currentConnection);
},
reset: () => {
// @todo: what should we do about this? Do we still need it?
// if you are on a SPA with multiple flows, we want to make sure that the store gets resetted
// when you switch pages. Does this reset solves this? Currently it always gets called. This
// leads to an emtpy nodes array at the beginning.
// set({ ...getInitialState() });
},
reset: () => set({ ...getInitialState() }),
}),
Object.is
);