From 7833da44eade217e3ce60f5b511701bc715a8339 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claude=CC=81ric=20Demers?= Date: Sat, 8 Jan 2022 12:26:48 -0500 Subject: [PATCH] Fix resize observer not always being connected --- .changeset/droppable-resize-observer.md | 2 +- .changeset/use-node-ref.md | 3 ++- packages/core/src/hooks/useDroppable.ts | 12 +++++++++++- packages/utilities/src/hooks/useNodeRef.ts | 11 +++++++++-- 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/.changeset/droppable-resize-observer.md b/.changeset/droppable-resize-observer.md index 97169363..a8db5d83 100644 --- a/.changeset/droppable-resize-observer.md +++ b/.changeset/droppable-resize-observer.md @@ -21,7 +21,7 @@ interface ResizeObserverConfig { } ``` -By default, only the current droppable is re-measured when a resize event is observed. However, this may not be suitable for all use-cases. When an element resizes, it can affect the layout and position of other elements, such that it may be necessary to re-measure other droppable nodes in response to that single resize event. The `recomputeIds` property can be used to specify which droppable `id`s should be re-measured in response to resize events being observed. +By default, only the current droppable is scheduled to be re-measured when a resize event is observed. However, this may not be suitable for all use-cases. When an element resizes, it can affect the layout and position of other elements, such that it may be necessary to re-measure other droppable nodes in response to that single resize event. The `recomputeIds` property can be used to specify which droppable `id`s should be re-measured in response to resize events being observed. For example, the `useSortable` preset re-computes the measurements of all sortable elements after the element that resizes, so long as they are within the same `SortableContext` as the element that resizes, since it's highly likely that their layout will also shift. diff --git a/.changeset/use-node-ref.md b/.changeset/use-node-ref.md index c21d2bba..459d8883 100644 --- a/.changeset/use-node-ref.md +++ b/.changeset/use-node-ref.md @@ -2,4 +2,5 @@ '@dnd-kit/utilities': patch --- -The `useNodeRef` hook's `onChange` argument now receives both the current node and the previous node that were attached to the ref. +- The `useNodeRef` hook's `onChange` argument now receives both the current node and the previous node that were attached to the ref. +- The `onChange` argument is only called if the previous node differs from the current node diff --git a/packages/core/src/hooks/useDroppable.ts b/packages/core/src/hooks/useDroppable.ts index f48f2678..dc11f03e 100644 --- a/packages/core/src/hooks/useDroppable.ts +++ b/packages/core/src/hooks/useDroppable.ts @@ -31,7 +31,7 @@ export interface UseDroppableArguments { const ID_PREFIX = 'Droppable'; const defaultResizeObserverConfig = { - timeout: 50, + timeout: 25, }; export function useDroppable({ @@ -110,6 +110,16 @@ export function useDroppable({ const [nodeRef, setNodeRef] = useNodeRef(handleNodeChange); const dataRef = useLatestValue(data); + useEffect(() => { + if (!resizeObserver || !nodeRef.current) { + return; + } + + resizeObserver.disconnect(); + resizeObserverConnected.current = false; + resizeObserver.observe(nodeRef.current); + }, [nodeRef, resizeObserver]); + useIsomorphicLayoutEffect( () => { dispatch({ diff --git a/packages/utilities/src/hooks/useNodeRef.ts b/packages/utilities/src/hooks/useNodeRef.ts index 060c7058..7d3fca9d 100644 --- a/packages/utilities/src/hooks/useNodeRef.ts +++ b/packages/utilities/src/hooks/useNodeRef.ts @@ -1,18 +1,25 @@ import {useRef, useCallback} from 'react'; +import {useLatestValue} from './useLatestValue'; + export function useNodeRef( onChange?: ( newElement: HTMLElement | null, previousElement: HTMLElement | null ) => void ) { + const onChangeRef = useLatestValue(onChange); const node = useRef(null); const setNodeRef = useCallback( (element: HTMLElement | null) => { - onChange?.(element, node.current); + if (element !== node.current) { + onChangeRef.current?.(element, node.current); + } + node.current = element; }, - [onChange] + //eslint-disable-next-line + [] ); return [node, setNodeRef] as const;