커스텀 훅 분리 및 react query 최적화

This commit is contained in:
hyeonsu
2025-09-03 14:57:52 +09:00
parent 63c7b80391
commit 4654a571f4
10 changed files with 527 additions and 230 deletions

View File

@@ -14,23 +14,10 @@ import { useCodes, useDeleteCode, useReorderCodes } from "@/hooks/queries/useCod
import type { CodeInfo } from "@/types/commonCode";
// Drag and Drop
import {
DndContext,
closestCenter,
KeyboardSensor,
PointerSensor,
useSensor,
useSensors,
DragOverlay,
type DragStartEvent,
type DragEndEvent,
} from "@dnd-kit/core";
import {
arrayMove,
SortableContext,
sortableKeyboardCoordinates,
verticalListSortingStrategy,
} from "@dnd-kit/sortable";
import { DndContext, DragOverlay } from "@dnd-kit/core";
import { SortableContext, verticalListSortingStrategy } from "@dnd-kit/sortable";
import { useDragAndDrop } from "@/hooks/useDragAndDrop";
import { useSearchAndFilter } from "@/hooks/useSearchAndFilter";
interface CodeDetailPanelProps {
categoryCode: string;
@@ -42,35 +29,36 @@ export function CodeDetailPanel({ categoryCode }: CodeDetailPanelProps) {
const deleteCodeMutation = useDeleteCode();
const reorderCodesMutation = useReorderCodes();
// 로컬 상태
const [searchTerm, setSearchTerm] = useState("");
const [showActiveOnly, setShowActiveOnly] = useState(false);
// 검색 및 필터링 훅 사용
const {
searchTerm,
setSearchTerm,
showActiveOnly,
setShowActiveOnly,
filteredItems: filteredCodes,
} = useSearchAndFilter(codes, {
searchFields: ["code_name", "code_value"],
});
// 모달 상태
const [showFormModal, setShowFormModal] = useState(false);
const [editingCode, setEditingCode] = useState<CodeInfo | null>(null);
const [showDeleteModal, setShowDeleteModal] = useState(false);
const [deletingCode, setDeletingCode] = useState<CodeInfo | null>(null);
// 드래그 상태
const [activeId, setActiveId] = useState<string | null>(null);
// Drag and Drop 센서
const sensors = useSensors(
useSensor(PointerSensor),
useSensor(KeyboardSensor, {
coordinateGetter: sortableKeyboardCoordinates,
}),
);
// 필터링된 코드 목록
const filteredCodes = codes.filter((code) => {
const matchesSearch =
code.code_name.toLowerCase().includes(searchTerm.toLowerCase()) ||
code.code_value.toLowerCase().includes(searchTerm.toLowerCase());
const matchesActive = !showActiveOnly || code.is_active === "Y";
return matchesSearch && matchesActive;
// 드래그 앤 드롭 훅 사용
const dragAndDrop = useDragAndDrop({
items: filteredCodes,
onReorder: async (reorderedItems) => {
await reorderCodesMutation.mutateAsync({
categoryCode,
codes: reorderedItems.map((item) => ({
codeValue: item.id,
sortOrder: item.sortOrder,
})),
});
},
getItemId: (code) => code.code_value,
});
// 새 코드 생성
@@ -108,38 +96,7 @@ export function CodeDetailPanel({ categoryCode }: CodeDetailPanelProps) {
}
};
// 드래그 시작 핸들러
const handleDragStart = (event: DragStartEvent) => {
setActiveId(event.active.id as string);
};
// 드래그 앤 드롭 처리
const handleDragEnd = async (event: DragEndEvent) => {
setActiveId(null);
const { active, over } = event;
if (over && active.id !== over.id) {
const oldIndex = filteredCodes.findIndex((code) => code.code_value === active.id);
const newIndex = filteredCodes.findIndex((code) => code.code_value === over.id);
const newOrder = arrayMove(filteredCodes, oldIndex, newIndex);
// 순서 업데이트를 위한 데이터 준비
const reorderData = newOrder.map((code, index) => ({
codeValue: code.code_value,
sortOrder: index + 1,
}));
try {
await reorderCodesMutation.mutateAsync({
categoryCode,
codes: reorderData,
});
} catch (error) {
console.error("코드 순서 변경 실패:", error);
}
}
};
// 드래그 앤 드롭 로직은 useDragAndDrop 훅에서 처리
if (!categoryCode) {
return (
@@ -213,12 +170,7 @@ export function CodeDetailPanel({ categoryCode }: CodeDetailPanelProps) {
</div>
) : (
<div className="p-2">
<DndContext
sensors={sensors}
collisionDetection={closestCenter}
onDragStart={handleDragStart}
onDragEnd={handleDragEnd}
>
<DndContext {...dragAndDrop.dndContextProps}>
<SortableContext
items={filteredCodes.map((code) => code.code_value)}
strategy={verticalListSortingStrategy}
@@ -237,10 +189,10 @@ export function CodeDetailPanel({ categoryCode }: CodeDetailPanelProps) {
</SortableContext>
<DragOverlay>
{activeId ? (
{dragAndDrop.activeItem ? (
<div className="cursor-grabbing rounded-lg border border-gray-300 bg-white p-3 shadow-lg">
{(() => {
const activeCode = filteredCodes.find((code) => code.code_value === activeId);
const activeCode = dragAndDrop.activeItem;
if (!activeCode) return null;
return (
<div className="flex items-start justify-between">