import { useEffect, useRef } from "react"; import { logger } from "@/utils/logger"; /** * 트랜잭션 이벤트 리스너 훅 - 성능 및 메모리 누수 방지 개선 버전 */ export const useTransactionsEvents = ( loadTransactions: () => void, refreshKey: number ) => { // 바운싱 방지 및 이벤트 제어를 위한 참조 const isProcessingRef = useRef(false); const timeoutIdsRef = useRef([]); // 타임아웃 클리어 도우미 함수 const clearAllTimeouts = () => { timeoutIdsRef.current.forEach((id) => window.clearTimeout(id)); timeoutIdsRef.current = []; }; useEffect(() => { logger.info("[이벤트] 이벤트 리스너 설정"); // 이벤트 핸들러 - 부하 조절(throttle) 적용 const handleEvent = (name: string, delay = 200) => { return (e?: any) => { // 이미 처리 중인 경우 건너뜀 if (isProcessingRef.current) { return; } logger.info(`[이벤트] ${name} 이벤트 감지:`, e?.detail?.type || ""); isProcessingRef.current = true; // 딜레이 적용 (이벤트 폭주 방지) const timeoutId = window.setTimeout(() => { loadTransactions(); isProcessingRef.current = false; // 타임아웃 ID 목록에서 제거 timeoutIdsRef.current = timeoutIdsRef.current.filter( (id) => id !== timeoutId ); }, delay); // 타임아웃 ID 기록 (나중에 정리하기 위함) timeoutIdsRef.current.push(timeoutId); }; }; // 각 이벤트별 핸들러 생성 const handleTransactionUpdate = handleEvent("트랜잭션 업데이트", 150); const handleTransactionDelete = handleEvent("트랜잭션 삭제", 200); const handleTransactionChange = handleEvent("트랜잭션 변경", 150); const handleStorageEvent = (e: StorageEvent) => { if (e.key === "transactions" || e.key === null) { handleEvent("스토리지", 150)(); } }; const handleFocus = handleEvent("포커스", 200); // 이벤트 리스너 등록 window.addEventListener("transactionUpdated", handleTransactionUpdate); window.addEventListener("transactionDeleted", handleTransactionDelete); window.addEventListener( "transactionChanged", handleTransactionChange as EventListener ); window.addEventListener("storage", handleStorageEvent); window.addEventListener("focus", handleFocus); // 초기 데이터 로드 if (!isProcessingRef.current) { loadTransactions(); } // 클린업 함수 return () => { logger.info("[이벤트] 이벤트 리스너 정리"); // 모든 이벤트 리스너 제거 window.removeEventListener("transactionUpdated", handleTransactionUpdate); window.removeEventListener("transactionDeleted", handleTransactionDelete); window.removeEventListener( "transactionChanged", handleTransactionChange as EventListener ); window.removeEventListener("storage", handleStorageEvent); window.removeEventListener("focus", handleFocus); // 모든 진행 중인 타임아웃 정리 clearAllTimeouts(); // 처리 상태 초기화 isProcessingRef.current = false; }; }, [loadTransactions, refreshKey]); };