diff --git a/packages/compass-components/src/hooks/use-throttled-props.tsx b/packages/compass-components/src/hooks/use-throttled-props.tsx new file mode 100644 index 00000000000..4dab1e44797 --- /dev/null +++ b/packages/compass-components/src/hooks/use-throttled-props.tsx @@ -0,0 +1,46 @@ +import { useEffect, useRef, useState } from 'react'; + +const DEFAULT_REFRESH_RATE_MS = 250; + +export const useThrottledProps = >( + props: T, + refreshRate: number = DEFAULT_REFRESH_RATE_MS +): T => { + // Throttling mechanism for Component content updates. + const lastUpdateMS = useRef(0); + const pendingUpdate = useRef(null); + const [throttledProps, setThrottledProps] = useState(props); + + // Throttle props updating. This ensures we don't run + // into broken state bugs with ReactFlow like COMPASS-9738. + useEffect(() => { + const now = Date.now(); + const timeSinceLastUpdate = now - lastUpdateMS.current; + + const updateProps = () => { + lastUpdateMS.current = Date.now(); + setThrottledProps(props); + }; + + if (timeSinceLastUpdate >= refreshRate) { + updateProps(); + } else { + if (pendingUpdate.current) { + clearTimeout(pendingUpdate.current); + } + + // Schedule update for the remaining time. + const remainingTime = refreshRate - timeSinceLastUpdate; + pendingUpdate.current = setTimeout(updateProps, remainingTime); + } + + return () => { + if (pendingUpdate.current) { + clearTimeout(pendingUpdate.current); + pendingUpdate.current = null; + } + }; + }, [props, refreshRate]); + + return throttledProps; +}; diff --git a/packages/compass-components/src/index.ts b/packages/compass-components/src/index.ts index ffacf0f8226..83d02c33e66 100644 --- a/packages/compass-components/src/index.ts +++ b/packages/compass-components/src/index.ts @@ -152,6 +152,7 @@ export { Theme, ThemeProvider, } from './hooks/use-theme'; +export { useThrottledProps } from './hooks/use-throttled-props'; export { ContentWithFallback, FadeInPlaceholder, diff --git a/packages/compass-data-modeling/src/components/diagram-editor.tsx b/packages/compass-data-modeling/src/components/diagram-editor.tsx index 859b11cc8a2..9436fb57512 100644 --- a/packages/compass-data-modeling/src/components/diagram-editor.tsx +++ b/packages/compass-data-modeling/src/components/diagram-editor.tsx @@ -29,6 +29,7 @@ import { useDarkMode, useDrawerActions, useDrawerState, + useThrottledProps, rafraf, } from '@mongodb-js/compass-components'; import { cancelAnalysis, retryAnalysis } from '../store/analysis-process'; @@ -324,6 +325,37 @@ const DiagramContent: React.FunctionComponent<{ [onAddNewFieldToCollection] ); + const diagramProps = useMemo( + () => ({ + isDarkMode, + title: diagramLabel, + edges, + nodes, + onAddFieldToNodeClick: onClickAddFieldToCollection, + onNodeClick, + onPaneClick, + onEdgeClick, + onFieldClick, + onNodeDragStop, + onConnect, + }), + [ + isDarkMode, + diagramLabel, + edges, + nodes, + onClickAddFieldToCollection, + onNodeClick, + onPaneClick, + onEdgeClick, + onFieldClick, + onNodeDragStop, + onConnect, + ] + ); + + const throttledDiagramProps = useThrottledProps(diagramProps); + return (
)}