nextjs: Hydration failed because the initial UI does not match what was rendered on the server.

sig03
4 min readJun 6, 2022

--

nextjs를 기반으로 토이 프로젝트를 진행해 보고 있다. 토큰값을 기반으로 public page, private page를 구분하려고 하는데 찾다보니 HoC로 처리하는 방법이 있다.

렌더링하려는 페이지를 상위 컴포넌트로 감싼다. 상위 컴포넌트에 토큰을 체크하는 로직을 넣어 토큰이 있으면 protected page, 없으면 public page로 돌린다.

아래의 예제를 참고했다.

그런데 적용하고 나니 protected 페이지에서 아래와 같은 에러가 발생했다.

Error: Hydration failed because the initial UI does not match what was rendered on the server.Error: There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.

서버에서 렌더링 된 것과 클라이언트에서 렌더링 된 것에 차이가 있어 뭐가 잘 안되나 보다. 디버깅을 해 보니 hoc에서 발생한 문제다. 참조한 소스에서 브라우저이면 protected page를 렌더링하고 아니면 null을 뿌리게 되어 있는데 그 null을 뿌리는 부분때문에 에러가 난다.

추정하기로 if (typeof window !== ‘undefined’) 소스때문에 서버에서는 null을 렌더링하는데 브라우저에서는 다른 페이지를 렌더링하니 서버와 클라이언트간에 다른 ui를 렌더링해서 문제가 발생하는게 아닌가 싶다. 아마 csr, ssr 기능에 에 포인트가 맞춰져 있는 nextjs의 특성때문에 발생한 문제로 보인다. only csr로 렌더링하면 문제가 안 생길거 같기도 하고. 일단 서버에서 렌더링하는 부분을 기존 null에서 클라이언트에서 렌더링 하는 내용으로 동일하게 맞춰주니 에러가 안 난다.

import { useRouter } from "next/router";const withAuth = (WrappedComponent) => {
return (props) => {

if (typeof window !== "undefined") {
const Router = useRouter();

const accessToken = localStorage.getItem("accessToken");

if (!accessToken) {
Router.replace("/");
return null;
}

return <WrappedComponent {...props} />;
}
//아래 리턴하는 부분을 null에서 브라우저 리턴 부분과 똑같게 바꿔줌
return <WrappedComponent {...props} />;
};
};

export default withAuth;

--

--

sig03
sig03

No responses yet