diff --git a/src/components/SplitPane.tsx b/src/components/SplitPane.tsx index 6fc8f277..701c0778 100644 --- a/src/components/SplitPane.tsx +++ b/src/components/SplitPane.tsx @@ -14,6 +14,7 @@ import { useResizer } from '../hooks/useResizer'; import { useKeyboardResize } from '../hooks/useKeyboardResize'; import { convertToPixels, distributeSizes } from '../utils/calculations'; import { cn } from '../utils/classNames'; +import { useIsomorphicLayoutEffect } from '../utils/useIsomorphicLayoutEffect'; const DEFAULT_CLASSNAME = 'split-pane'; const MIN_PANES = 2; @@ -158,8 +159,9 @@ export function SplitPane(props: SplitPaneProps) { ); // Sync paneSizes with controlled size props when they change - // This handles the case where parent state is reset (e.g., clicking a "Reset" button) - useEffect(() => { + // This handles the case where parent state is reset (e.g., clicking a "Reset" button). + // Runs in a layout effect so the new width is committed in the same paint as possible content changes. + useIsomorphicLayoutEffect(() => { if (containerSize === 0) return; // Check if any pane has a controlled size prop diff --git a/src/hooks/useResizer.ts b/src/hooks/useResizer.ts index 348fc613..6b3a9893 100644 --- a/src/hooks/useResizer.ts +++ b/src/hooks/useResizer.ts @@ -5,6 +5,7 @@ import { snapToPoint, applyStep, } from '../utils/calculations'; +import { useIsomorphicLayoutEffect } from '../utils/useIsomorphicLayoutEffect'; /** * Options for the useResizer hook. @@ -85,8 +86,10 @@ export function useResizer(options: UseResizerOptions): UseResizerResult { onResizeEndRef.current = onResizeEnd; // Sync sizes from props when not dragging (React 19 compatible) + // Layout effect so an external size change (e.g. a controlled pane collapsing) + // updates the rendered width in lockstep with consumer content. const sizesRef = useRef(sizes); - useEffect(() => { + useIsomorphicLayoutEffect(() => { if ( !isDragging && JSON.stringify(sizes) !== JSON.stringify(sizesRef.current) diff --git a/src/utils/useIsomorphicLayoutEffect.ts b/src/utils/useIsomorphicLayoutEffect.ts new file mode 100644 index 00000000..4e79d557 --- /dev/null +++ b/src/utils/useIsomorphicLayoutEffect.ts @@ -0,0 +1,7 @@ +import { useEffect, useLayoutEffect } from 'react'; + +/** + * `useLayoutEffect` that degrades to `useEffect` during server rendering. + */ +export const useIsomorphicLayoutEffect = + typeof window === 'undefined' ? useEffect : useLayoutEffect;