[NEXT] hydration 관해서

강동욱·2024년 5월 12일
0

문제상황

export default function Table({ }: Props) {

  const isClient = typeof window !== 'undefined';

  return <div>{isClient ? 'hi' : 'hi server'}</div>;
}

Error: Text content does not match server-rendered HTML.

위와 같은 코드를 작성하면 다음과 같은 에러가 발생합니다. 그렇다면 이런 에러가 발생하는 이유는 무엇일까요?

Hydration

오류를 해결하기위해선 먼저 hydration이라는 개념을 알고 가야할 것 같습니다.

기본적으로 Nexjs에서는 서버에서 HTML을 생성하고 최소한의 자바스크립트 코드를 생성된 HTML에 연결하고 브라우저에게 보냅니다.

브라우저에서 페이지를 로딩하면 자바스크립트가 완전히 인터랙티브하게 바뀌는데 이러한 개념을 Hydration이라고 합니다. 쉽게 말해서 수분이 없는 HTML에 수분을 보충해주는 상상을 하면 이해하기 쉬울 것 입니다.

위의 사진은 모두 브라우저 입장에서 그려진 사진입니다. CSR일 경우 브라우저는 빈 HTML을 받게되고 클라이언트에서 DOM을 생성하고 JS 코드를 파싱하여 화면에 렌더링 합니다. 반면에 SSR은 서버에서 미리 렌더링 되어진(Pre-Rendering) 건조된 HTML을 받고 클라이언트에서는 수분을 채워넣는 역할 즉 js코드를 인터랙티브 하게 만들어 줍니다.

Hydration error 문제점

hydration error가 발생했을 때는 리액트가 hydration error를 핸들링 할 수 있지만 react가 직접 핸들링하면 서버에서 생성된 기존 UI를 클라이언트에서 바꾸는 것이므로 깜박임 현상이 일어날 수 있습니다(아래 사진 참고). 이럴경우 좋지 못한 UX를 경험으로 이어질 수도 있고 또 다른 문제는 좋지 못한 SEO, 성능저하, 잘못된 이벤트 핸들러 연결로도 이어질 수 있습니다. 자세한 내용은 리액트 hydrate root를 참조하면 좋을 것 같습니다.

해결 방법

useEffect 사용해서 의도적으로 Initial rendering 피하기

변경 전

export default function Table({ }: Props) {

  const isClient = typeof window !== 'undefined';

  return <div>{isClient ? 'hi' : 'hi server'}</div>;
}

변경 후

export default function Table({ }: Props) {

  const [isClient, setIsClient] = useState(false);
  
  useEffect(()=> {
  	if(typeof window !== undefined) {
      setIsClient(true)
    }
  }, [])

  return <div>{isClient ? 'hi' : 'hi server'}</div>;
}

dynamic 이용하기

useEffect도 다시 리렌더링을 일으키기 때문에 초기에 리렌더링을 하는 것은 아까와 같이 깜박임 현상도 있을 수 있어 좋은 UX가 되지 못할 수도 있습니다.
Next에서는 클라이언트 컴포넌트의 HTML도 서버에서 렌더링이 된다. 이때 클라이언트에서 컴포넌트를 렌더링을 시키려면 dynamic함수 안에 ssr:false 옵션을 추가해서 ssr 기능을 스킵하게 만들면 됩니다. 참고로 dynamic함수는 React.lazy()와 Suspense를 합친 기능이라고 생각하면 됩니다. 옵션에 loading: () => <p>Loading...</p> 도 추가할 수 있습니다.

const NoSSR = dynamic(() => import('@monorepo/shi/src/Table'), { ssr: false });

export default function App() {
	return (
      <div>
    	<p>hi</p>
        <NoSSR/>
      </div>
    )
} 
profile
차근차근 개발자

0개의 댓글