https://nextjs.org/docs/messages/react-hydration-error
애플리케이션을 렌더링하는 동안, 서버 사이드 렌더링(SSR/SSG)된 React
트리와 브라우저에서 첫 렌더링 시 렌더링된 React
트리 간에 차이가 있었습니다. 첫 번째 렌더링은 React
의 Hydration
기능 중 하나입니다.
이러한 차이로 인해 React
트리가 DOM
과 동기화되지 않아 예기치 않은 콘텐츠/속성이 나타날 수 있습니다.
일반적으로 이 문제는 라이브러리나 애플리케이션 코드에서, 서버 사이드 렌더링(SSR/SSG
)과 브라우저에서의 렌더링 사이에 차이가 발생할 수 있는 것에 의존하고 있을 때 발생합니다. 이러한 예로는 컴포넌트 렌더링에서 window
를 사용하는 것이 있습니다.
예시:
function MyComponent() {
// 이 조건문은 `window`에 의존합니다. 브라우저의 첫 렌더링에서는 `color` 변수가 다를 수 있습니다.
const color = typeof window !== 'undefined' ? 'red' : 'blue'
// color가 프롭으로 전달되기 때문에 서버 측에서 렌더링된 것과 브라우저 첫 렌더링에서 렌더링된 것 간에 불일치가 발생합니다.
return <h1 className={`title ${color}`}>Hello World!</h1>
}
해결 방법:
// 브라우저에서만 실행되는 useEffect를 사용하여 첫 번째 렌더링이 다르게 되는 것을 방지할 수 있습니다. Hydration에서 실행됩니다.
import { useEffect, useState } from 'react'
function MyComponent() {
// 기본값은 'blue'이며, 이 값은 서버 측 렌더링과 브라우저 첫 렌더링(하이드레이션) 모두에서 사용됩니다.
const [color, setColor] = useState('blue')
// Hydration에서 useEffect가 호출됩니다. `window`는 `useEffect`에서 사용할 수 있습니다.
// 이 예시에서는 window를 사용하므로 브라우저에서만 사용됩니다. window에서 무언가를 읽어야 하는 경우에는 문제 없습니다.
// `setColor`를 호출하여 useEffect에서 렌더링을 트리거하면 하이드레이션 후 "브라우저 특정 값"이 사용 가능합니다. 이 경우에는 'red'입니다.
useEffect(() => setColor('red'), [])
// color가 상태로 전달되기 때문에 서버 측에서 렌더링된 것과 브라우저 첫 렌더링에서 렌더링된 것 간에 불일치가 발생하지 않습니다. useEffect가 실행된 후에는 color가 'red'로 설정됩니다.
return <h1 className={title ${color}}>Hello World!</h1>
}
다른 예시:
div
가 p
태그 내부에 있으면 잘못된 HTML
이므로 hydration
불일치가 발생할 수 있습니다.
export const IncorrectComponent = () => {
return (
<p>
<div>
This is not correct and should never be done because the p tag has been
abused
</div>
<Image src="/vercel.svg" alt="" width="30" height="30" />
</p>
)
}
해결 방법:
export const CorrectComponent = () => {
return (
<div>
<div>
This is correct and should work because a div is really good for this
task.
</div>
<Image src="/vercel.svg" alt="" width="30" height="30" />
</div>
)
}
CSS-in-JS
라이브러리의 일반적인 원인:
Styled Components
/ Emotion
을 사용할 때
CSS-in-JS
라이브러리가 서버 사이드 렌더링(SSR/SSG)에 대한 설정이 되어 있지 않으면 hydration
불일치가 발생할 가능성이 높습니다. 이 경우 애플리케이션은 해당 라이브러리의 Next.js
예제를 따라야 합니다. 예를 들어 pages/_document
가 누락되었거나 Babel
플러그인이 추가되지 않은 경우입니다.Styled Components
의 해결 방법:Next.js
12.1+에서 Styled Components
를 SWC와 함께 사용하려면 Next.js
구성에 컴파일러 옵션으로 추가해야 합니다. https://github.com/vercel/next.js/tree/canary/examples/with-styled-componentsBabel
을 사용하여 Styled Components
를 사용하려면 pages/_document
와 Babel
플러그인이 필요합니다. https://github.com/vercel/next.js/tree/canary/examples/with-styled-components-`babel`Emotion
의 해결 방법: https://github.com/vercel/next.js/tree/canary/examples/with-emotion다른 CSS-in-JS
라이브러리를 사용할 때:
Styled Components
/ Emotion
과 유사하게 CSS-in-JS
라이브러리는 examples 디렉토리에 있는 설정이 필요합니다.Local Overrides:
Chrome 개발자 도구에서 로컬 오버라이드가 활성화되어 있을 수 있습니다. 이 경우, 서버 사이드 렌더링(SSR)이 출력한 HTML과 다른 HTML이 제공됩니다. 또한 view-source에 표시되지 않기 때문에 무슨 일이 일어나고 있는지 이해하기 어려울 수 있습니다.
iOS에서의 일반적인 원인:
iOS는 텍스트 콘텐츠에서 전화번호, 이메일 주소 및 기타 데이터를 감지하여 링크로 변환하려고 합니다. 이로 인해 hydration 불일치가 발생할 수 있습니다. 이 문제는 다음 메타 태그를 사용하여 해결할 수 있습니다:
<meta name="format-detection" content="telephone=no, date=no, email=no, address=no" />