Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs-site/docs/api/components/sortable-item.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ Returns: `itemKey`, `index`, `isActive` (SharedValue), `activeItemId` (SharedVal
- Shift values come from `shiftsRef` SharedValue (keyed by item key)
- Visibility controlled by `hoverReadySV` + `draggedIdSV` — hidden when being dragged
- Measures itself on layout and stores in `itemMeasurements` Map
- Calls `onItemSnapEnd` when snap-back completes (triggers reorder finalization)
- Calls `onItemSnapEndRef.current` when snap-back completes (triggers reorder finalization)
- Respects reduced motion via `useReducedMotion()`

## Related
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ Returns: `itemKey`, `index`, `isActive` (SharedValue), `activeItemId` (SharedVal
- Shift values come from `shiftsRef` SharedValue (keyed by item key)
- Visibility controlled by `hoverReadySV` + `draggedIdSV` — hidden when being dragged
- Measures itself on layout and stores in `itemMeasurements` Map
- Calls `onItemSnapEnd` when snap-back completes (triggers reorder finalization)
- Calls `onItemSnapEndRef.current` when snap-back completes (triggers reorder finalization)
- Respects reduced motion via `useReducedMotion()`

## Related
Expand Down
2 changes: 1 addition & 1 deletion src/SortableContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ export const SortableContainer = ({
// calls the latest version, even if it has a stale _internal reference
// (e.g., after MATCH path skips FlatList re-render).
useLayoutEffect(() => {
sortable._internal.onItemSnapEnd = finalizeDrag;
sortable._internal.onItemSnapEndRef.current = finalizeDrag;
}, [sortable._internal, finalizeDrag]);

// ── Auto-scroll ─────────────────────────────────────────────────────
Expand Down
4 changes: 2 additions & 2 deletions src/SortableItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ const SortableItemInner = ({
rawData,
originalIndexes,
scrollPosition,
onItemSnapEnd,
onItemSnapEndRef,
fixedKeys,
} = sortable._internal;

Expand Down Expand Up @@ -221,7 +221,7 @@ const SortableItemInner = ({
draxViewProps.onDragDrop?.(event);
}}
onSnapEnd={(snapData) => {
onItemSnapEnd?.();
onItemSnapEndRef.current?.();
draxViewProps.onSnapEnd?.(snapData);
}}
onMeasure={(measurements) => {
Expand Down
9 changes: 8 additions & 1 deletion src/hooks/useSortableList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,13 @@ export const useSortableList = <T,>(
// ── Drag tracking (refs, no re-render) ────────────────────────────
const draggedDisplayIndexRef = useRef<number | undefined>(undefined);
const dragStartIndexRef = useRef<number | undefined>(undefined);
/**
* Holds the `finalizeDrag` callback registered by `SortableContainer`.
* A ref (not a plain property) so `SortableItem` reads the latest value at
* call time — `_internal` is rebuilt every render, so a value stored on it
* directly is always `undefined` for consumers that destructure at render.
*/
const onItemSnapEndRef = useRef<(() => void) | undefined>(undefined);
/**
* Pending reorder during drag. Tracks the desired display order
* as indices into rawData. Updated by moveDraggedItem (ref, not state).
Expand Down Expand Up @@ -1023,7 +1030,7 @@ export const useSortableList = <T,>(
getMeasurementByOriginalIndex,
dropTargetPositionSV,
dropTargetVisibleSV,
onItemSnapEnd: undefined as (() => void) | undefined,
onItemSnapEndRef,
draggedDisplayIndexRef,
dragStartIndexRef,
shiftsRef,
Expand Down
2 changes: 1 addition & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -812,7 +812,7 @@ export interface SortableListInternal<T> {
/** Called by SortableItem's onSnapEnd to finalize the drag.
* Stored as a ref so the latest finalizeDrag is always called,
* even if SortableItem has a stale _internal reference. */
onItemSnapEnd?: () => void;
onItemSnapEndRef: RefObject<(() => void) | undefined>;
/** Current display index of the dragged item (updated during live reorder) */
draggedDisplayIndexRef: RefObject<number | undefined>;
/** Original display index where the drag started */
Expand Down