로그인/로그아웃으로 버튼 컴포넌트를 바꾸면서 처리했던 에러 작성
import Image from 'next/image'
import { SearchForm } from './_/SearchForm'
import Link from 'next/link'
import Logo from '/public/assets/logo.png'
import { getCategories } from '@/services/server-action'
import { CartButton } from './_/CartButton'
import { context } from '@/lib/context'
// import { SignOutButton } from './_/SignOutButton'
import AuthButtons from './_/AuthButtons '
export const Header = async () => {
const { data: categories } = await getCategories()
const { isLogin } = context()
return (
<header className="relative m-auto max-w-screen-lg flex h-[60px] justify-between items-center">
<div className="flex items-center gap-2">
<Link href={'/'}>
<Image height={40} src={Logo} alt="logo"></Image>
</Link>
</div>
<div className="z-50 absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2">
<SearchForm categories={categories} />
</div>
<div className="flex gap-2 items-center">
<CartButton isLogin={isLogin} />
{/* {isLogin ? (
<SignOutButton />
) : (
<Link className="h-9 flex text-white items-center py-1 px-4 rounded-md bg-blue-600" href={'/sign-in'}>
Sign In
</Link>
)} */}
<AuthButtons />
</div>
</header>
)
}
'use client'
import React, { useEffect, useState } from 'react'
import { useAuthStore } from '@/store/useAuthStore'
import { Button } from '../ui/button'
import browserClient from '@/utils/supabase/client'
import Link from 'next/link'
export default function AuthButtons() {
const [hydrated, setHydrated] = useState(false) // Hydration 체크
const { isLogin, setLogin } = useAuthStore((state) => ({
isLogin: state.isLogin,
setLogin: state.setLogin
}))
useEffect(() => {
const checkSession = async () => {
const {
data: { session }
} = await browserClient.auth.getSession()
setLogin(!!session)
}
checkSession()
setHydrated(true)
}, [setLogin])
if (!hydrated) {
return null
}
const handleSignOut = async () => {
await browserClient.auth.signOut()
setLogin(false)
}
return (
<>
{isLogin ? (
<Button onClick={handleSignOut}>Sign Out</Button>
) : (
<Link className="h-9 flex text-white items-center py-1 px-4 rounded-md bg-blue-600" href={'/sign-in'}>
Sign In
</Link>
)}
</>
)
}
새로고침 시 Hydration failed because the initial UI does not match what was rendered on the server 오류로 서버에서 렌더링된 HTML과 클라이언트 측 초기 랜더링 된 HTML이 불일치하여 생기는 에러는 useEffect로 클라이언트 측에서 상태를 변경할 때 발생하는데
해결방법은 useEffect로 상태를 초기화하여 해결 할 수 있다. 클라이언트에서 로그인 상태를 결정하고 서버측에서는 로그인 상태를 신경쓰지 않도록 처리하여 서버 렌더링 시에는 loading 상태나 기본 상태를 사용하고 클라이언트측에서만 로그인 여부를 결정한다
로컬 호스트에 zustand로 로그인 상태를 저장하고 불러오는 과정에서 생긴 오류.
처음에는 새로고침시 로그인 버튼이 풀리는 상태였지만 버튼을 따로 컴포넌트로 적용 하고나서 저러한 오류가 발생하였고, persist로 로컬 스토리지에 저장하고, 서버측과 클라이언트 측을 분리하여 사용하였다.
AuthButtons 컴포넌트를 만들 때, client.ts에 저장되어있는 browser supabase를 적용하여야 하기 때문에 파일을 분리 적용하였고 setHydrated state를 만들어 로딩시에 Hydration 실패를 방지하였다. 컴포넌트가 완전히 로드 된 후, 상태를 변경하기 위해 사용한 것
서버 측에서 로그인 상태를 고려하지 않고, 클라이언트에서만 로그인 여부를 결정하는 방식으로 서버 렌더링과 클라이언트 렌더링의 일관성을 유지하기 위해 hydrated state 적용