체인의정석

Next.js Hydration 에러 처리 (Rainbow Wallet 사용 시 적용 필요) 본문

개발/frontend

Next.js Hydration 에러 처리 (Rainbow Wallet 사용 시 적용 필요)

체인의정석 2025. 4. 2. 11:02
728x90
반응형

Next.js에서 자주 마주치는 Hydration Error는 **SSR(Server-Side Rendering)**과 CSR(Client-Side Rendering) 사이의 차이 때문에 발생

🔍 Hydration이란?

  • Next.js는 서버에서 HTML을 먼저 렌더링한 후, 클라이언트에서 React가 해당 HTML에 이벤트 핸들러와 상태를 붙이는 과정을 "Hydration"이라고함

⚠️ Hydration Error란?

서버에서 렌더링된 HTML과 클라이언트에서 렌더링되는 결과가 다를 때 발생하는 오류

예를 들어:

const [count, setCount] = useState(Math.random());
  • 이 코드는 서버와 클라이트에서 Math.random()의 결과가 다르기 때문에, 두 버전의 DOM이 달라지고, hydration 시 에러가 나


🧯 대표적인 원인들


useState, useEffect가 렌더링에 영향을 줄 때 서버/클라이언트 결과 불일치
window 객체 접근 SSR 환경엔 window가 없음
Math.random(), Date.now() 등 클라이언트 의존 값 사용 예측 불가능 값은 SSR과 CSR에서 다르게 렌더링됨

내 경우에는 Rainbow wallet 사용시에 해당 오류가 났다.

지갑이 연결되어 있는지 체크하는 로직이 HTML이 랜더링 될 당시에는 없기 때문에 이러한 오류가 발생하는것.
이러한 문제를 막기위해 mounted라는 변수를 통해 랜더링이 된 이후에 변수를 mount하는 방식을 사용하였다.

const [mounted, setMounted] = useState(false);

useEffect(() => {
    setMounted(true);
}, []);

if (!mounted) return null;

이런식으로 mount가 안되기 전엔 null을 리턴하는 방식으로 하여 클라이언트 단에서의 랜더링과 서버사이드 랜더링을 일치하게 만들어준다.

import { useAccount } from 'wagmi';
import { useRouter } from 'next/navigation';

    const { isConnected, address } = useAccount();
    const router = useRouter();

    useEffect(() => {
        if (isConnected) {
            console.log(`✅ 로그인 성공 - 연결된 지갑 주소: ${address}`);
            router.push('/');
        }
    }, [isConnected, address, router]);

useAccount는 wagmi에서 사용중이며, useRouter는 로그인 성공시 라우팅을 시키는 부분이다.
해당 hook을 사용하게 되면 블록체인 지갑에서 연결여부와 주소를 가져올 수 있고, router를 통해서 로그인에 성공할 시 메인페이지로 들어가도록 만들 수 있다.

그리고 해당 변수를 바로 사용하면 화면에서 보여주는 데이터는 서버사이드 랜더링 된 데이터와 다르기 때문에 Hydration오류가 나기 때문에 useEffect를 써서 랜더링이 모두 된 후에 변수를 할당해서 사용하는 식으로 구현해야하는 것이다.

 

 

728x90
반응형
Comments