Unhandled Runtime Error
Error: Hydration failed because the initial UI does not match what was rendered on the server.
Next.js가 SSR 방식을 사용하기 때문에 이 코드가 없으면 아래의 오류가 발생했고 이를 해결하고자 window의 type 검사 코드를 넣으니 Hydration error가 발생한 것이었죠.
Hydrate를 간략하게만 설명하자면 서버사이드에서 rendering된 정적 페이지와 번들링된 js코드를 클라이언트에게 보낸 후 js코드가 HTML DOM 위에서 다시 rendering 되면서 서로 매칭되는 과정입니다.
즉 이 코드가 들어가면서
if (typeof window === 'object') {
return createPortal(
children,
document.getElementById(selector) as HTMLElement
);
}
서버사이드에서 pre-rendering된 React 트리와 브라우저에서 처음 rendering되는 React 트리가 달랐기 때문에 발생한 에러였죠.
next.js 공식 링크
문서를 참고하여 위에서 작성한 Portal 코드를 아래와 같이 수정했더니 문제가 해결되었습니다.
import { FC, ReactNode, useEffect, useState } from "react";
import { createPortal } from "react-dom";
interface PortalProps {
children: ReactNode;
selector: string;
}
const Portal: FC<PortalProps> = ({ children, selector }) => {
const [element, setElement] = useState<HTMLElement | null>(null);
useEffect(() => {
setElement(document.getElementById(selector));
}, [element]);
if (element) return createPortal(children, element);
return null;
};
export default Portal;
ssr서 document 객체에 접근하는 것을 막기 위해 if (typeof window === 'object') 코드를 삽입한 것이었는데, csr에서 실행되는 useEffect 내에서 document 객체를 참조하면 문제를 해결할 수 있었습니다.