[에러 메시지] Error: Hydration failed because the initial UI does not match what was rendered on the server.

Daisy🌷·2024년 5월 15일
0
post-custom-banner

에러가 발생했는데 nextjs 공식 문서 링크와 함께 나타나고 있어서 공식 문서 링크로 들어갔다.

Text content does not match server-rendered HTML

👾 이 에러가 발생한 이유

애플리케이션을 렌더링하는 동안 서버에서 미리 렌더링 된 React 트리와 브라우저에서 처음 렌더링하는 동안 렌더링 된 React 트리 사이에 차이가 있었기 때문이다. (hydration)

Hydration은 React가 이벤트 핸들러를 첨부하여 서버에서 미리 렌더링된 HTML을 완전한 interactive 애플리케이션으로 변환하는 것이다.

위의 hydration 설명이 이해가 안된다면 따로 공부한 내용을 정리해서 글로 남겨두었으니 참고! ✍️ hydration

👾 일반적인 원인

  1. 잘못된 HTML 태그 중첩
    • 다른 <p> 태그에 중첩된 <p>
    • <div> 태그 안에 중첩된 <p> 태그
    • <p> 태그 안에 중첩된 <ul> 또는 <ol>
    • Interactive Content가 중첩된 경우 (<a>, <button>)
  2. 렌더링 로직에서 typeof window !== 'undefined' 과 같은 check 사용
  3. 렌더링 로직에 window 또는 localStorage와 같은 browser-only API 사용
  4. 렌더링 로직에서 Date() 생성자와 같은 time-dependent API 사용
  5. HTML을 수정하는 Brower extensions
  6. 잘못 구성된 CSS-in-JS 라이브러리
  7. Cloudflare 자동 축소와 같이 html 응답 수정을 시도하는 잘못 구성된 Edge/CDN.

나의 경우는 3번 원인 때문에 해당 에러가 발생하고 있었다.

✨ 해결 방법

useEffect 를 사용하여 클라이언트에서만 실행하기

hydration mismatch를 방지하기 위해 컴포넌트가 초기 클라이언트 측 렌더링(CSR) 시와 동일한 콘텐츠를 서버 측에서 렌더링하는지 확인한다. useEffect 훅을 사용하여 의도적으로 클라이언트에서 다른 콘텐츠를 렌더링할 수 있다.

import { useState, useEffect } from 'react'
 
export default function App() {
  const [isClient, setIsClient] = useState(false)
 
  useEffect(() => {
    setIsClient(true)
  }, [])
 
  return <h1>{isClient ? 'This is never prerendered' : 'Prerendered'}</h1>
}

React가 hydration되는 동안 useEffect 가 호출된다. 즉. window 와 같은 브라우저 API를 hydration mismatch 없이 사용할 수 있다.

공식 문서만 보고서는 이해가 잘 안 갔다.. 보충 설명!

  • useEffect 훅은 클라이언트 측에서만 실행된다. 이 훅은 컴포넌트가 렌더링된 후에 실행되므로, 브라우저 환경에서만 동작하는 코드(ex:window 객체에 접근하는 코드)를 안전하게 사용할 수 있다.
  • useEffect 훅을 사용하여 클라이언트에서만 상태를 변경함으로써, 서버와 클라이언트의 초기 렌더링 결과를 동일하게 유지할 수 있다.
  • 이는 hydration mismatch를 방지하고, React가 서버에서 받은 HTML과 클라이언트에서 렌더링된 HTML이 일치하도록 보장한다.
  • 따라서 useEffect 를 사용하여 클라이언트에서만 실행하는 것이 해당 에러의 해결책이 될 수 있는 것이다.

📚 참고 자료

profile
Frontend Developer
post-custom-banner

0개의 댓글