Refactor TransactionDeleteAlert component
Refactor TransactionDeleteAlert component to improve maintainability.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
|
||||
import React, { useState, useRef, useEffect } from 'react';
|
||||
import React from 'react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Trash2, Loader2 } from 'lucide-react';
|
||||
import {
|
||||
@@ -13,75 +13,22 @@ import {
|
||||
AlertDialogTitle,
|
||||
AlertDialogTrigger
|
||||
} from '@/components/ui/alert-dialog';
|
||||
import { useDeleteAlert } from '@/hooks/transactions/useDeleteAlert';
|
||||
|
||||
interface TransactionDeleteAlertProps {
|
||||
onDelete: () => Promise<boolean> | boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 트랜잭션 삭제 확인 다이얼로그 - 완전히 개선된 버전
|
||||
* 삭제 중복 방지, 상태 관리 개선, 메모리 누수 방지 로직 추가
|
||||
* 트랜잭션 삭제 확인 다이얼로그 - 리팩토링된 버전
|
||||
* 삭제 로직을 useDeleteAlert 훅으로 분리하여 컴포넌트 간소화
|
||||
*/
|
||||
const TransactionDeleteAlert: React.FC<TransactionDeleteAlertProps> = ({ onDelete }) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [isDeleting, setIsDeleting] = useState(false);
|
||||
|
||||
// 타임아웃 참조 저장 (메모리 누수 방지용)
|
||||
const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
|
||||
// 클린업 함수 - 메모리 누수 방지
|
||||
const clearTimeouts = () => {
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current);
|
||||
timeoutRef.current = null;
|
||||
}
|
||||
};
|
||||
|
||||
// 컴포넌트 언마운트 시 모든 타임아웃 제거
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
clearTimeouts();
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleDelete = async () => {
|
||||
// 이미 삭제 중이면 중복 실행 방지
|
||||
if (isDeleting) return;
|
||||
|
||||
try {
|
||||
// 삭제 상태 활성화
|
||||
setIsDeleting(true);
|
||||
|
||||
// 다이얼로그 즉시 닫기 (UI 응답성 개선)
|
||||
setIsOpen(false);
|
||||
|
||||
// UI 애니메이션 완료 후 삭제 실행
|
||||
timeoutRef.current = setTimeout(async () => {
|
||||
try {
|
||||
// 삭제 함수 실행
|
||||
await onDelete();
|
||||
} catch (error) {
|
||||
console.error('삭제 처리 오류:', error);
|
||||
} finally {
|
||||
// 모든 작업 완료 후 상태 초기화 (약간 지연)
|
||||
timeoutRef.current = setTimeout(() => {
|
||||
setIsDeleting(false);
|
||||
}, 100);
|
||||
}
|
||||
}, 150);
|
||||
} catch (error) {
|
||||
console.error('삭제 핸들러 오류:', error);
|
||||
setIsDeleting(false);
|
||||
setIsOpen(false);
|
||||
}
|
||||
};
|
||||
// 삭제 관련 로직을 커스텀 훅으로 분리
|
||||
const { isOpen, isDeleting, handleDelete, handleOpenChange } = useDeleteAlert(onDelete);
|
||||
|
||||
return (
|
||||
<AlertDialog open={isOpen} onOpenChange={(open) => {
|
||||
// 삭제 중에는 상태 변경 방지
|
||||
if (isDeleting && !open) return;
|
||||
setIsOpen(open);
|
||||
}}>
|
||||
<AlertDialog open={isOpen} onOpenChange={handleOpenChange}>
|
||||
<AlertDialogTrigger asChild>
|
||||
<Button
|
||||
type="button"
|
||||
|
||||
74
src/hooks/transactions/useDeleteAlert.ts
Normal file
74
src/hooks/transactions/useDeleteAlert.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
|
||||
import { useState, useRef, useEffect } from 'react';
|
||||
|
||||
/**
|
||||
* 트랜잭션 삭제 알림 관련 로직을 담당하는 커스텀 훅
|
||||
*/
|
||||
export const useDeleteAlert = (onDelete: () => Promise<boolean> | boolean) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [isDeleting, setIsDeleting] = useState(false);
|
||||
|
||||
// 타임아웃 참조 저장 (메모리 누수 방지용)
|
||||
const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
|
||||
// 클린업 함수 - 메모리 누수 방지
|
||||
const clearTimeouts = () => {
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current);
|
||||
timeoutRef.current = null;
|
||||
}
|
||||
};
|
||||
|
||||
// 컴포넌트 언마운트 시 모든 타임아웃 제거
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
clearTimeouts();
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleDelete = async () => {
|
||||
// 이미 삭제 중이면 중복 실행 방지
|
||||
if (isDeleting) return;
|
||||
|
||||
try {
|
||||
// 삭제 상태 활성화
|
||||
setIsDeleting(true);
|
||||
|
||||
// 다이얼로그 즉시 닫기 (UI 응답성 개선)
|
||||
setIsOpen(false);
|
||||
|
||||
// UI 애니메이션 완료 후 삭제 실행
|
||||
timeoutRef.current = setTimeout(async () => {
|
||||
try {
|
||||
// 삭제 함수 실행
|
||||
await onDelete();
|
||||
} catch (error) {
|
||||
console.error('삭제 처리 오류:', error);
|
||||
} finally {
|
||||
// 모든 작업 완료 후 상태 초기화 (약간 지연)
|
||||
timeoutRef.current = setTimeout(() => {
|
||||
setIsDeleting(false);
|
||||
}, 100);
|
||||
}
|
||||
}, 150);
|
||||
} catch (error) {
|
||||
console.error('삭제 핸들러 오류:', error);
|
||||
setIsDeleting(false);
|
||||
setIsOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 다이얼로그 상태 관리
|
||||
const handleOpenChange = (open: boolean) => {
|
||||
// 삭제 중에는 상태 변경 방지
|
||||
if (isDeleting && !open) return;
|
||||
setIsOpen(open);
|
||||
};
|
||||
|
||||
return {
|
||||
isOpen,
|
||||
isDeleting,
|
||||
handleDelete,
|
||||
handleOpenChange
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user