.claude/skills/dnd-kit-drag-event-gotchas/SKILL.md
Fix duplicate state updates when using dnd-kit for drag-and-drop. Use when: (1) State changes fire multiple times during a single drag operation, (2) History/audit entries are duplicated for intermediate positions, (3) handleDragOver is updating state that should only change on drop. Covers the difference between onDragOver (continuous) and onDragEnd (final).
npx skillsauth add Dbochman/dotfiles dnd-kit-drag-event-gotchasInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
When using dnd-kit's onDragOver handler to track state changes (like movement
history), you get duplicate entries for every column/container the dragged item
passes through, not just the final destination.
handleDragOverhandleDragEnd, not handleDragOverhandleDragStart using a refhandleDragEnd before recording changes// Track starting position
const dragStartRef = useRef<string | null>(null);
const handleDragStart = (event: DragStartEvent) => {
const startContainer = findContainerByItemId(event.active.id);
dragStartRef.current = startContainer?.id || null;
};
const handleDragOver = (event: DragOverEvent) => {
// Only move items between containers here
// Do NOT record history or analytics
};
const handleDragEnd = (event: DragEndEvent) => {
const startId = dragStartRef.current;
const endContainer = findContainerByItemId(event.active.id);
dragStartRef.current = null; // Reset for next drag
// Only record if actually moved to different container
if (startId && endContainer && startId !== endContainer.id) {
// Record history ONCE here
recordMovement(event.active.id, startId, endContainer.id);
}
};
After implementing:
Before fix (problematic):
history: [
{ from: "ideas", to: "todo", timestamp: "...42.716Z" },
{ from: "todo", to: "ideas", timestamp: "...42.720Z" },
{ from: "ideas", to: "todo", timestamp: "...42.727Z" },
{ from: "todo", to: "in-progress", timestamp: "...42.757Z" },
// ... many more oscillating entries
]
After fix (correct):
history: [
{ from: "ideas", to: "in-progress", timestamp: "...42.800Z" }
]
onDragOver fires continuously as the drag passes over drop targetsonDragOver for visual state (hover effects, placeholder positioning)onDragEnd for persistent state changes (database updates, history)onDragOvertools
Use exact configured Reolink cameras through the local Home Hub for availability and power status, fresh stills, visual commentary, protected Dylan/Julia/household sharing, and reversible spotlight control. Supports trusted owner tasks and explicitly scoped proactive automations; not for Nest or Ring cameras, arbitrary recipients, recordings, account changes, or raw camera APIs.
data-ai
Privately manage Dylan and Julia's household plant inventory and care history by physical location, bed, and exact Flower Cam view. Use for confirmed plant onboarding from camera conversations, camera- or bed-filtered inventory, record corrections, individual or whole-bed care, and private filtered exports. Pair with reolink-camera when an owner asks about plants visible in Flower Cam images.
testing
Inspect and control the physically secured Reachy Mini at Crosstown through ClawBody. Use for requests to check Reachy, look around, express an emotion, play any official emotion or dance preset, speak proactively, mute or unmute its microphone, stop movement, or describe what its camera sees.
tools
Handle Reachy/iMessage handoffs, selective durable memory, forgetting, and diagnostics; automatic context comes from the gateway plugin.