fix(nav): TopNav auth 구독 안정화 + 로그아웃 UX 보강
코드 리뷰 후속: - (I-1) useMemo로 supabase client 안정화 → 매 렌더 re-subscribe 제거 - (I-2) getUser() → getSession() → first paint flash 거의 제거 (localStorage 동기 읽기) - (M-1) 로그아웃 router.push → router.replace → 보호 페이지 백스택 잔존 방지 - (M-2) 모바일 로그아웃 button transition-colors 추가 (데스크톱과 일관) Defer (별도 검토): - M-3 로그인 시 Try now 사라짐 — marketing 결정 필요 - M-5 잔여 flash — Phase 2 server prop hydration 시 완전 제거 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { usePathname, useRouter } from 'next/navigation';
|
import { usePathname, useRouter } from 'next/navigation';
|
||||||
import { useState, useEffect } from 'react';
|
import { useMemo, useState, useEffect } from 'react';
|
||||||
import { createClient } from '@/lib/supabase/client';
|
import { createClient } from '@/lib/supabase/client';
|
||||||
import type { User } from '@supabase/supabase-js';
|
import type { User } from '@supabase/supabase-js';
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ const LINKS = [
|
|||||||
export default function TopNav() {
|
export default function TopNav() {
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const supabase = createClient();
|
const supabase = useMemo(() => createClient(), []);
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [scrolled, setScrolled] = useState(false);
|
const [scrolled, setScrolled] = useState(false);
|
||||||
const [user, setUser] = useState<User | null>(null);
|
const [user, setUser] = useState<User | null>(null);
|
||||||
@@ -32,8 +32,8 @@ export default function TopNav() {
|
|||||||
// Supabase auth state subscription (Sidebar.tsx:93-103 패턴)
|
// Supabase auth state subscription (Sidebar.tsx:93-103 패턴)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let mounted = true;
|
let mounted = true;
|
||||||
supabase.auth.getUser().then(({ data }) => {
|
supabase.auth.getSession().then(({ data }) => {
|
||||||
if (mounted) setUser(data.user ?? null);
|
if (mounted) setUser(data.session?.user ?? null);
|
||||||
});
|
});
|
||||||
const { data: { subscription } } = supabase.auth.onAuthStateChange((_event, session) => {
|
const { data: { subscription } } = supabase.auth.onAuthStateChange((_event, session) => {
|
||||||
if (mounted) setUser(session?.user ?? null);
|
if (mounted) setUser(session?.user ?? null);
|
||||||
@@ -47,7 +47,7 @@ export default function TopNav() {
|
|||||||
const handleLogout = async () => {
|
const handleLogout = async () => {
|
||||||
await supabase.auth.signOut();
|
await supabase.auth.signOut();
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
router.push('/');
|
router.replace('/');
|
||||||
router.refresh();
|
router.refresh();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -214,7 +214,7 @@ export default function TopNav() {
|
|||||||
</Link>
|
</Link>
|
||||||
<button
|
<button
|
||||||
onClick={handleLogout}
|
onClick={handleLogout}
|
||||||
className="flex-1 py-3 text-center rounded-full text-sm font-bold"
|
className="flex-1 py-3 text-center rounded-full text-sm font-bold transition-colors"
|
||||||
style={{ border: '1px solid rgba(255,255,255,0.15)', color: 'var(--kx-on-surface)', background: 'transparent' }}
|
style={{ border: '1px solid rgba(255,255,255,0.15)', color: 'var(--kx-on-surface)', background: 'transparent' }}
|
||||||
>
|
>
|
||||||
로그아웃
|
로그아웃
|
||||||
|
|||||||
Reference in New Issue
Block a user