fix: stabilize useDragManager callback refs and containerHandlers memo

Remove activeDrag from drag-start dependency arrays to prevent
unnecessary re-renders during drag. Wrap containerHandlers in
useMemo for consistent reference stability.
This commit is contained in:
Jannis Braun
2026-03-20 20:39:52 +01:00
parent 2952799d00
commit eb6f4bf94e
+7 -7
View File
@@ -1,4 +1,4 @@
import { useState, useCallback, useEffect, type RefObject } from 'react'; import { useState, useCallback, useEffect, useMemo, type RefObject } from 'react';
export type DragType = 'channel' | 'category' | 'voiceUser'; export type DragType = 'channel' | 'category' | 'voiceUser';
@@ -39,18 +39,18 @@ export function useDragManager(opts: UseDragManagerOpts) {
// --- Channel/Category drag handlers --- // --- Channel/Category drag handlers ---
const handleChannelDragStart = useCallback((e: React.DragEvent, channelId: string) => { const handleChannelDragStart = useCallback((e: React.DragEvent, channelId: string) => {
if (!canManage || activeDrag !== null) return; if (!canManage) return;
e.dataTransfer.effectAllowed = 'move'; e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text/plain', channelId); // Firefox requires setData for drag to work e.dataTransfer.setData('text/plain', channelId); // Firefox requires setData for drag to work
setActiveDrag({ type: 'channel', dragId: channelId }); setActiveDrag({ type: 'channel', dragId: channelId });
}, [canManage, activeDrag]); }, [canManage]);
const handleCategoryDragStart = useCallback((e: React.DragEvent, categoryId: string) => { const handleCategoryDragStart = useCallback((e: React.DragEvent, categoryId: string) => {
if (!canManage || activeDrag !== null) return; if (!canManage) return;
e.dataTransfer.effectAllowed = 'move'; e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text/plain', categoryId); // Firefox requires setData for drag to work e.dataTransfer.setData('text/plain', categoryId); // Firefox requires setData for drag to work
setActiveDrag({ type: 'category', dragId: categoryId }); setActiveDrag({ type: 'category', dragId: categoryId });
}, [canManage, activeDrag]); }, [canManage]);
const handleLayoutDragOver = useCallback((e: React.DragEvent, targetId: string, targetType: 'channel' | 'category') => { const handleLayoutDragOver = useCallback((e: React.DragEvent, targetId: string, targetType: 'channel' | 'category') => {
if (!activeDrag || activeDrag.type === 'voiceUser') return; if (!activeDrag || activeDrag.type === 'voiceUser') return;
@@ -107,10 +107,10 @@ export function useDragManager(opts: UseDragManagerOpts) {
clearState(); clearState();
}, [activeDrag, dropTarget, onChannelDrop, onCategoryDrop, clearState]); }, [activeDrag, dropTarget, onChannelDrop, onCategoryDrop, clearState]);
const containerHandlers = { const containerHandlers = useMemo(() => ({
onDrop: handleContainerDrop, onDrop: handleContainerDrop,
onDragOver: handleContainerDragOver, onDragOver: handleContainerDragOver,
}; }), [handleContainerDrop, handleContainerDragOver]);
// --- Voice user drag handlers --- // --- Voice user drag handlers ---