diff --git a/src/pages/center/MyPage.jsx b/src/pages/center/MyPage.jsx index 37b725c..4024bbe 100644 --- a/src/pages/center/MyPage.jsx +++ b/src/pages/center/MyPage.jsx @@ -16,35 +16,167 @@ import DefaultProfile from '@/assets/images/elder-basic-profile.png'; export default function MyPage() { const navigate = useNavigate(); const [profileSrc, setProfileSrc] = useState(DefaultProfile); + const [performanceMetrics, setPerformanceMetrics] = useState({ + componentMountTime: null, + dataLoadStartTime: null, + dataLoadEndTime: null, + imageLoadStartTime: null, + imageLoadEndTime: null, + }); const { data: managerProfile, isLoading, saveManagerProfile } = useManagerProfile(); const { isEditMode, toggleEditMode, setFormData } = useManagerProfileStore(); const setHeaderProps = useHeaderPropsStore((state) => state.setHeaderProps); const clearHeaderProps = useHeaderPropsStore((state) => state.clearHeaderProps); + // 컴포넌트 마운트 시간 측정 useEffect(() => { + const mountTime = performance.now(); + setPerformanceMetrics((prev) => ({ ...prev, componentMountTime: mountTime })); + console.log('🚀 MyPage 컴포넌트 마운트 시작'); + setHeaderProps({ type: 'logo' }); return () => clearHeaderProps(); }, [clearHeaderProps, setHeaderProps]); - // fallback profile image + // React Query 데이터 로딩 상태 추적 useEffect(() => { + if (!isLoading && managerProfile) { + const dataLoadEndTime = performance.now(); + setPerformanceMetrics((prev) => ({ + ...prev, + dataLoadEndTime, + dataLoadStartTime: prev.dataLoadStartTime || prev.componentMountTime, + })); + + const dataLoadTime = (prev) => + prev.dataLoadEndTime && prev.dataLoadStartTime + ? (prev.dataLoadEndTime - prev.dataLoadStartTime).toFixed(2) + : 'N/A'; + + console.log('📊 React Query 데이터 로딩 완료:', { + isLoading, + hasData: !!managerProfile, + dataSource: 'cache', // react-query 캐시에서 가져온 경우 + loadTime: dataLoadTime(performanceMetrics), + }); + } + }, [isLoading, managerProfile, performanceMetrics]); + + // 프로필 이미지 로딩 및 성능 측정 + useEffect(() => { + if (!managerProfile) return; + + const imageLoadStartTime = performance.now(); + setPerformanceMetrics((prev) => ({ ...prev, imageLoadStartTime })); + console.log('🖼️ 프로필 사진 로딩 시작'); + // if profile image exists, set profileSrc if (managerProfile?.imgAddress) { + console.log('📸 기존 프로필 이미지 사용:', managerProfile.imgAddress); setProfileSrc(managerProfile.imgAddress); + const imageLoadEndTime = performance.now(); + setPerformanceMetrics((prev) => ({ ...prev, imageLoadEndTime })); + + const imageLoadTime = (imageLoadEndTime - imageLoadStartTime).toFixed(2); + console.log(`⚡ 프로필 사진 로딩 완료 (기존 이미지): ${imageLoadTime}ms`); + + // 전체 성능 메트릭 출력 + logPerformanceMetrics(); } else { // if profile image doesn't exist, set default profile image + console.log('🔄 기본 프로필 이미지 로딩 중...'); fetchDefaultImage() - .then((url) => setProfileSrc(url)) - .catch(() => setProfileSrc(DefaultProfile)); + .then((url) => { + setProfileSrc(url); + const imageLoadEndTime = performance.now(); + setPerformanceMetrics((prev) => ({ ...prev, imageLoadEndTime })); + + const imageLoadTime = (imageLoadEndTime - imageLoadStartTime).toFixed(2); + console.log(`⚡ 프로필 사진 로딩 완료 (기본 이미지): ${imageLoadTime}ms`); + console.log('📸 기본 이미지 URL:', url); + + // 전체 성능 메트릭 출력 + logPerformanceMetrics(); + }) + .catch(() => { + setProfileSrc(DefaultProfile); + const imageLoadEndTime = performance.now(); + setPerformanceMetrics((prev) => ({ ...prev, imageLoadEndTime })); + + const imageLoadTime = (imageLoadEndTime - imageLoadStartTime).toFixed(2); + console.log(`⚡ 프로필 사진 로딩 완료 (fallback): ${imageLoadTime}ms`); + console.log('⚠️ 기본 이미지 로딩 실패, fallback 이미지 사용'); + + // 전체 성능 메트릭 출력 + logPerformanceMetrics(); + }); } }, [managerProfile]); + // 전체 성능 메트릭 로깅 함수 + const logPerformanceMetrics = () => { + const metrics = performanceMetrics; + const now = performance.now(); + + console.group('📈 전체 성능 메트릭'); + console.log( + '🚀 컴포넌트 마운트 시간:', + metrics.componentMountTime ? `${(now - metrics.componentMountTime).toFixed(2)}ms` : 'N/A', + ); + console.log( + '📊 데이터 로딩 시간:', + metrics.dataLoadEndTime && metrics.dataLoadStartTime + ? `${(metrics.dataLoadEndTime - metrics.dataLoadStartTime).toFixed(2)}ms` + : 'N/A', + ); + console.log( + '🖼️ 이미지 로딩 시간:', + metrics.imageLoadEndTime && metrics.imageLoadStartTime + ? `${(metrics.imageLoadEndTime - metrics.imageLoadStartTime).toFixed(2)}ms` + : 'N/A', + ); + console.log( + '⚡ 총 로딩 시간:', + metrics.componentMountTime ? `${(now - metrics.componentMountTime).toFixed(2)}ms` : 'N/A', + ); + console.groupEnd(); + }; + const handleImgError = useCallback(() => { + const startTime = performance.now(); + console.log('❌ 이미지 로딩 에러 발생, 대체 이미지 로딩 시작'); + fetchDefaultImage() - .then((url) => setProfileSrc(url)) - .catch(() => setProfileSrc(DefaultProfile)); - }, []); + .then((url) => { + setProfileSrc(url); + const endTime = performance.now(); + console.log(`⚡ 대체 이미지 로딩 완료: ${(endTime - startTime).toFixed(2)}ms`); + console.log('📸 대체 이미지 URL:', url); + + // 에러 복구 후 성능 메트릭 업데이트 + setPerformanceMetrics((prev) => ({ + ...prev, + imageLoadEndTime: endTime, + imageLoadStartTime: startTime, + })); + logPerformanceMetrics(); + }) + .catch(() => { + setProfileSrc(DefaultProfile); + const endTime = performance.now(); + console.log(`⚡ fallback 이미지 로딩 완료: ${(endTime - startTime).toFixed(2)}ms`); + console.log('⚠️ 대체 이미지 로딩도 실패, 최종 fallback 이미지 사용'); + + // 에러 복구 후 성능 메트릭 업데이트 + setPerformanceMetrics((prev) => ({ + ...prev, + imageLoadEndTime: endTime, + imageLoadStartTime: startTime, + })); + logPerformanceMetrics(); + }); + }, [performanceMetrics]); // if profile data doesn't exist, redirect to signin page useEffect(() => { @@ -123,6 +255,22 @@ export default function MyPage() { if (isLoading || !managerProfile) return ; + console.log('📊 현재 프로필 사진 상태:', { + profileSrc, + hasManagerProfile: !!managerProfile, + hasImgAddress: !!managerProfile?.imgAddress, + imgSeq: managerProfile?.imgSeq, + reactQueryStatus: { + isLoading, + isFetching: false, // react-query의 isFetching 상태도 확인 가능 + dataSource: 'cache', // 캐시에서 가져온 데이터인지 확인 + }, + zustandState: { + isEditMode, + hasFormData: !!useManagerProfileStore.getState().formData, + }, + }); + return (
{/* profile header */}