33import { useEffect , useState } from 'react' ;
44import { useRouter } from 'next/navigation' ;
55import { useAuthStore } from '@/src/features/auth/store' ;
6+ import { Landing } from '@/src/shared/components/Landing' ;
67
78/**
8- * 루트 진입점. 별도 랜딩 화면 없이 인증 상태에 따라 리다이렉트한다 .
9- * - 로그인 상태(토큰 보유) → /dashboard
10- * - 비로그인 → /login
9+ * 루트 진입점. 인증 상태에 따라 화면을 분기한다 .
10+ * - 로그인 상태(토큰 보유) → /dashboard 로 리다이렉트
11+ * - 비로그인 → 랜딩 페이지(<Landing/>)를 렌더 (리다이렉트하지 않음)
1112 *
1213 * 토큰은 zustand persist(localStorage)에서 복원되지만, SSR/CSR 간
13- * 하이드레이션 미스매치를 피하려고 mount 이후에만 판별·이동한다.
14+ * 하이드레이션 미스매치를 피하려고 mount 이후에만 판별한다.
15+ * 마운트 전에는 깜빡임을 막기 위해 빈 화면을 잠깐 보여주고,
16+ * 마운트 후 토큰이 없으면 랜딩을, 토큰이 있으면 대시보드로 보낸다.
1417 */
1518export default function Home ( ) {
1619 const router = useRouter ( ) ;
@@ -22,14 +25,20 @@ export default function Home() {
2225 } , [ ] ) ;
2326
2427 useEffect ( ( ) => {
25- if ( mounted ) {
26- router . replace ( token ? '/dashboard' : '/login ') ;
28+ if ( mounted && token ) {
29+ router . replace ( '/dashboard' ) ;
2730 }
2831 } , [ mounted , token , router ] ) ;
2932
30- return (
31- < div className = "flex min-h-screen items-center justify-center bg-gray-50" >
32- < span className = "text-sm text-gray-500" > 로딩 중...</ span >
33- </ div >
34- ) ;
33+ // 인증된 사용자는 대시보드로 이동 중이므로 랜딩 대신 빈 화면을 잠깐 노출.
34+ if ( mounted && token ) {
35+ return (
36+ < div className = "flex min-h-screen items-center justify-center bg-gray-50" >
37+ < span className = "text-sm text-gray-500" > 로딩 중...</ span >
38+ </ div >
39+ ) ;
40+ }
41+
42+ // 미인증 방문자(또는 마운트 전)에게는 랜딩 페이지를 보여준다.
43+ return < Landing /> ;
3544}
0 commit comments