diff --git a/.changeset/use-latest-value.md b/.changeset/use-latest-value.md index 4dc0107e..a58b66f3 100644 --- a/.changeset/use-latest-value.md +++ b/.changeset/use-latest-value.md @@ -2,4 +2,4 @@ '@dnd-kit/utilities': minor --- -Introduced the `useLatestValue` hook, which returns a ref that holds the latest value of a given argument. +Introduced the `useLatestValue` hook, which returns a ref that holds the latest value of a given argument. Optionally, the second argument can be used to customize the dependencies passed to the effect. diff --git a/packages/core/src/components/DndContext/DndContext.tsx b/packages/core/src/components/DndContext/DndContext.tsx index a9b6e7ab..e902e273 100644 --- a/packages/core/src/components/DndContext/DndContext.tsx +++ b/packages/core/src/components/DndContext/DndContext.tsx @@ -13,6 +13,7 @@ import { add, getEventCoordinates, Transform, + useLatestValue, useIsomorphicLayoutEffect, useUniqueId, } from '@dnd-kit/utilities'; @@ -183,11 +184,12 @@ export const DndContext = memo(function DndContext({ const activeRef = useRef(null); const [activeSensor, setActiveSensor] = useState(null); const [activatorEvent, setActivatorEvent] = useState(null); - const latestProps = useRef(props); + const latestProps = useLatestValue(props, Object.values(props)); const draggableDescribedById = useUniqueId(`DndDescribedBy`, id); - const enabledDroppableContainers = useMemo(() => { - return droppableContainers.getEnabled(); - }, [droppableContainers]); + const enabledDroppableContainers = useMemo( + () => droppableContainers.getEnabled(), + [droppableContainers] + ); const { droppableRects, measureDroppableContainers, @@ -225,7 +227,6 @@ export const DndContext = memo(function DndContext({ const overNode = droppableContainers.getNodeFor( sensorContext.current.over?.id ); - const dragOverlay = useDragOverlayMeasuring({ measure: measuring?.dragOverlay?.measure, }); @@ -424,7 +425,8 @@ export const DndContext = memo(function DndContext({ }; } }, - [dispatch, draggableNodes] + // eslint-disable-next-line react-hooks/exhaustive-deps + [draggableNodes] ); const bindActivatorToSensorInstantiator = useCallback( @@ -465,14 +467,6 @@ export const DndContext = memo(function DndContext({ useSensorSetup(sensors); - useIsomorphicLayoutEffect( - () => { - latestProps.current = props; - }, - // eslint-disable-next-line react-hooks/exhaustive-deps - Object.values(props) - ); - useEffect(() => { if (activeId != null) { setIsDragging(true); @@ -489,27 +483,31 @@ export const DndContext = memo(function DndContext({ } }, [activeNodeRect, active]); - useEffect(() => { - const {onDragMove} = latestProps.current; - const {active, collisions, over} = sensorContext.current; + useEffect( + () => { + const {onDragMove} = latestProps.current; + const {active, collisions, over} = sensorContext.current; - if (!active) { - return; - } + if (!active) { + return; + } - const event: DragMoveEvent = { - active, - collisions, - delta: { - x: scrollAdjustedTranslate.x, - y: scrollAdjustedTranslate.y, - }, - over, - }; + const event: DragMoveEvent = { + active, + collisions, + delta: { + x: scrollAdjustedTranslate.x, + y: scrollAdjustedTranslate.y, + }, + over, + }; - setMonitorState({type: Action.DragMove, event}); - onDragMove?.(event); - }, [scrollAdjustedTranslate.x, scrollAdjustedTranslate.y]); + setMonitorState({type: Action.DragMove, event}); + onDragMove?.(event); + }, + // eslint-disable-next-line react-hooks/exhaustive-deps + [scrollAdjustedTranslate.x, scrollAdjustedTranslate.y] + ); useEffect( () => { diff --git a/packages/core/src/hooks/utilities/useDragOverlayMeasuring.ts b/packages/core/src/hooks/utilities/useDragOverlayMeasuring.ts index 2144ade2..2648c694 100644 --- a/packages/core/src/hooks/utilities/useDragOverlayMeasuring.ts +++ b/packages/core/src/hooks/utilities/useDragOverlayMeasuring.ts @@ -1,9 +1,5 @@ -import {useMemo, useCallback, useState, useRef} from 'react'; -import { - isHTMLElement, - useIsomorphicLayoutEffect, - useNodeRef, -} from '@dnd-kit/utilities'; +import {useMemo, useCallback, useState} from 'react'; +import {isHTMLElement, useNodeRef} from '@dnd-kit/utilities'; import {getMeasurableNode} from '../../utilities/nodes'; import {getClientRect} from '../../utilities/rect'; @@ -18,7 +14,6 @@ export function useDragOverlayMeasuring({ measure = getClientRect, }: Arguments): PublicContextDescriptor['dragOverlay'] { const [rect, setRect] = useState(null); - const measureRef = useRef(measure); const handleResize = useCallback( (entries: ResizeObserverEntry[]) => { for (const {target} of entries) { @@ -55,10 +50,6 @@ export function useDragOverlayMeasuring({ ); const [nodeRef, setRef] = useNodeRef(handleNodeChange); - useIsomorphicLayoutEffect(() => { - measureRef.current = measure; - }, [measure]); - return useMemo( () => ({ nodeRef, diff --git a/packages/utilities/src/hooks/useLatestValue.ts b/packages/utilities/src/hooks/useLatestValue.ts index 583d2d40..77d99bb6 100644 --- a/packages/utilities/src/hooks/useLatestValue.ts +++ b/packages/utilities/src/hooks/useLatestValue.ts @@ -2,14 +2,17 @@ import {useRef} from 'react'; import {useIsomorphicLayoutEffect} from './useIsomorphicLayoutEffect'; -export function useLatestValue(value: T) { +export function useLatestValue( + value: T, + dependencies = [value] +) { const valueRef = useRef(value); useIsomorphicLayoutEffect(() => { if (valueRef.current !== value) { valueRef.current = value; } - }, [value]); + }, dependencies); return valueRef; }