⚠️nextjs에서 만난 hydration 에러
Text content does not match server-rendered HTML.
프로젝트 개발 중에 심심치 않게 마주쳤던 문구인데 이는 공식문서에서도 언급하고 있는 hydration 에러이다.
https://nextjs.org/docs/messages/react-hydration-error
Text content does not match server-rendered HTML
Using App Router Features available in /app
nextjs.org
📃Hydarion 에러란?
공식문서에서는 이 에러에 대해 이렇게 설명하고 있다.
While rendering your application, there was a difference between the React tree that was pre-rendered from the server and the React tree that was rendered during the first render in the browser (hydration).
Hydration is when React converts the pre-rendered HTML from the server into a fully interactive application by attaching event handlers.
즉, hydartion에러란 서버에서 pre-render하여 만들어진 React tree와 브라우저에서 첫 번째로 렌더되는 React tree 간의 차이에 의해 발생하는 에러이다.
💡Hydration이란?
서버에서 pre-render하여 생성된 정적페이지(HTML)에 상호작용할 수 있도록 이벤트 핸들러를 바인딩하는 것이다.
❗Hydration 에러가 발생하는 원인
1. 잘못된 HTML 태그
<p> 태그 안에 <p> 태그 중첩, <div>태그 안에 <p> 태그 중첩, 상호작용하는(<a>, <button>, etc) 태그의 중첩 등 HTML 구조가 잘못 작성된 경우 발생할 수 있다.
2. 환경에 따라 달라지는 로직
typeof window !== 'undefined' 와 같이 운영 환경에 따라 달라지는 경우, 서버에서 생성한 HTML과 브라우저에서 렌더링되는 DOM tree가 달라질 수 있어 에러가 발생한다.
3. 브라우저에서만 사용가능한 APIs
브라우저에서만 사용 가능한 APIs (window, localStorage) 를 렌더링 로직에서 사용할 때 발생한다.
크게 이러한 이유로 Hydration 에러가 발생하게 된다.
🪄Hydration 에러 해결방법
만약 HTML의 잘못된 구조 등이 원인이라면 해당 부분을 수정해주면 되지만, 이외의 경우 아래와 같은 방법을 사용할 수 있다.
1. useEffect 사용하기
useEffect를 사용함으로써 hydration 과정에서 서버와 클라이언트가 동일하게 렌더링을 하고 이후에 동적 콘텐츠를 렌더링하도록 하는 것이다.
const [hydrated, setHydrated] = useState(false);
useEffect(() => {
setHydrated(true);
}, []);
if (!hydrated) return null;
이렇게 설정해두면 첫 번째 렌더링 때는 기본값 false이므로 null이 반환되어 아무것도 렌더링되지 않는다. 이 첫 번째 렌더링 과정에서 useEffect를 통해 setHydrated를 true로 변경하여 재렌더링을 촉진시켜 두 번째 렌더링이 일어나고, 이 땐 hydration 과정이 마친 상태이기 때문에 에러없이 정상적으로 화면이 렌더링이 되게 된다.
진행하던 프로젝트에서도 최상단인 _app 컴포넌트에서 위의 로직을 통해 hydration 에러를 방지함으로써 각 페이지에서 hydration 에러를 신경쓰지 않아도 되도록 하였다.
https://stackoverflow.com/questions/72673362/error-text-content-does-not-match-server-rendered-html
Error: Text content does not match server-rendered HTML
I'm trying to perform a simple algorithm in next.js and I'm getting this hydration errors. This is the code I'm using: import numeros from "../../functions/numberGenerators.js" export default
stackoverflow.com
2. SSR 비활성화하기
이러한 에러가 발생하는 페이지에서 SSR이 필요가 없다면 사전렌더링을 비활성화하는 방법으로도 에러를 해결할 수 있다.
import dynamic from 'next/dynamic'
const NoSSR = dynamic(() => import('../components/no-ssr'), { ssr: false })
export default function Page() {
return (
<div>
<NoSSR />
</div>
)
}
nextJS를 처음 사용해보면서 생각보다 빈번하게 hydration 에러를 겪었었다. 처음엔 각 페이지마다 관련 로직을 추가하였고 점차 페이지마다 관련해서 중복되는 로직이 많아져서 hook으로 빼자는 의견이 나왔었다. 그런데 사용하는 페이지가 많아진다면 hook을 사용하는 것도 반복작업이 될 수 있을 것 같아서 아예 최상단에서 hydration 에러를 체크하는 것으로 결정되었다.
이후 최적화 과정에서 관련 로직을 제거했을 때 성능이 올라가는 페이지가 있어서 분리하는 게 좋을까 하는 의견이 나와서 팀원분이 확인을 해보니 생각보다 많은 페이지에서 hydartion 체크가 필요해서 결국 기존대로 최상단에서 진행하게 되었다.
이처럼 프로젝트의 진행방향에 따라 최상단에서 할지, 각 페이지에서 할지, hook으로 만들지 정해서 사용한다면 hydration 에러 걱정은 끝!
관련해서 공식문서에도 내용이 있어서 크게 헤매지 않고 공부하면서 에러를 해결할 수 있어서 좋았다!
'개발 공부 > React' 카테고리의 다른 글
react slick 특정 슬라이드에서 dots 없애기 (0) | 2023.07.31 |
---|---|
[nextJS] 성능 최적화 하기(lighthouse, 빌드 용량 개선) (0) | 2023.07.25 |
[nextJS]일정 시간 이상 걸리는 페이지 이동만 로딩 처리 (0) | 2023.07.23 |
[next + tanstack query] 낙관적 업데이트 적용하기 (0) | 2023.07.22 |
무한스크롤 스크롤 위치 기억하기 (0) | 2023.07.10 |
⚠️nextjs에서 만난 hydration 에러
Text content does not match server-rendered HTML.
프로젝트 개발 중에 심심치 않게 마주쳤던 문구인데 이는 공식문서에서도 언급하고 있는 hydration 에러이다.
https://nextjs.org/docs/messages/react-hydration-error
Text content does not match server-rendered HTML
Using App Router Features available in /app
nextjs.org
📃Hydarion 에러란?
공식문서에서는 이 에러에 대해 이렇게 설명하고 있다.
While rendering your application, there was a difference between the React tree that was pre-rendered from the server and the React tree that was rendered during the first render in the browser (hydration).
Hydration is when React converts the pre-rendered HTML from the server into a fully interactive application by attaching event handlers.
즉, hydartion에러란 서버에서 pre-render하여 만들어진 React tree와 브라우저에서 첫 번째로 렌더되는 React tree 간의 차이에 의해 발생하는 에러이다.
💡Hydration이란?
서버에서 pre-render하여 생성된 정적페이지(HTML)에 상호작용할 수 있도록 이벤트 핸들러를 바인딩하는 것이다.
❗Hydration 에러가 발생하는 원인
1. 잘못된 HTML 태그
<p> 태그 안에 <p> 태그 중첩, <div>태그 안에 <p> 태그 중첩, 상호작용하는(<a>, <button>, etc) 태그의 중첩 등 HTML 구조가 잘못 작성된 경우 발생할 수 있다.
2. 환경에 따라 달라지는 로직
typeof window !== 'undefined' 와 같이 운영 환경에 따라 달라지는 경우, 서버에서 생성한 HTML과 브라우저에서 렌더링되는 DOM tree가 달라질 수 있어 에러가 발생한다.
3. 브라우저에서만 사용가능한 APIs
브라우저에서만 사용 가능한 APIs (window, localStorage) 를 렌더링 로직에서 사용할 때 발생한다.
크게 이러한 이유로 Hydration 에러가 발생하게 된다.
🪄Hydration 에러 해결방법
만약 HTML의 잘못된 구조 등이 원인이라면 해당 부분을 수정해주면 되지만, 이외의 경우 아래와 같은 방법을 사용할 수 있다.
1. useEffect 사용하기
useEffect를 사용함으로써 hydration 과정에서 서버와 클라이언트가 동일하게 렌더링을 하고 이후에 동적 콘텐츠를 렌더링하도록 하는 것이다.
const [hydrated, setHydrated] = useState(false);
useEffect(() => {
setHydrated(true);
}, []);
if (!hydrated) return null;
이렇게 설정해두면 첫 번째 렌더링 때는 기본값 false이므로 null이 반환되어 아무것도 렌더링되지 않는다. 이 첫 번째 렌더링 과정에서 useEffect를 통해 setHydrated를 true로 변경하여 재렌더링을 촉진시켜 두 번째 렌더링이 일어나고, 이 땐 hydration 과정이 마친 상태이기 때문에 에러없이 정상적으로 화면이 렌더링이 되게 된다.
진행하던 프로젝트에서도 최상단인 _app 컴포넌트에서 위의 로직을 통해 hydration 에러를 방지함으로써 각 페이지에서 hydration 에러를 신경쓰지 않아도 되도록 하였다.
https://stackoverflow.com/questions/72673362/error-text-content-does-not-match-server-rendered-html
Error: Text content does not match server-rendered HTML
I'm trying to perform a simple algorithm in next.js and I'm getting this hydration errors. This is the code I'm using: import numeros from "../../functions/numberGenerators.js" export default
stackoverflow.com
2. SSR 비활성화하기
이러한 에러가 발생하는 페이지에서 SSR이 필요가 없다면 사전렌더링을 비활성화하는 방법으로도 에러를 해결할 수 있다.
import dynamic from 'next/dynamic'
const NoSSR = dynamic(() => import('../components/no-ssr'), { ssr: false })
export default function Page() {
return (
<div>
<NoSSR />
</div>
)
}
nextJS를 처음 사용해보면서 생각보다 빈번하게 hydration 에러를 겪었었다. 처음엔 각 페이지마다 관련 로직을 추가하였고 점차 페이지마다 관련해서 중복되는 로직이 많아져서 hook으로 빼자는 의견이 나왔었다. 그런데 사용하는 페이지가 많아진다면 hook을 사용하는 것도 반복작업이 될 수 있을 것 같아서 아예 최상단에서 hydration 에러를 체크하는 것으로 결정되었다.
이후 최적화 과정에서 관련 로직을 제거했을 때 성능이 올라가는 페이지가 있어서 분리하는 게 좋을까 하는 의견이 나와서 팀원분이 확인을 해보니 생각보다 많은 페이지에서 hydartion 체크가 필요해서 결국 기존대로 최상단에서 진행하게 되었다.
이처럼 프로젝트의 진행방향에 따라 최상단에서 할지, 각 페이지에서 할지, hook으로 만들지 정해서 사용한다면 hydration 에러 걱정은 끝!
관련해서 공식문서에도 내용이 있어서 크게 헤매지 않고 공부하면서 에러를 해결할 수 있어서 좋았다!
'개발 공부 > React' 카테고리의 다른 글
react slick 특정 슬라이드에서 dots 없애기 (0) | 2023.07.31 |
---|---|
[nextJS] 성능 최적화 하기(lighthouse, 빌드 용량 개선) (0) | 2023.07.25 |
[nextJS]일정 시간 이상 걸리는 페이지 이동만 로딩 처리 (0) | 2023.07.23 |
[next + tanstack query] 낙관적 업데이트 적용하기 (0) | 2023.07.22 |
무한스크롤 스크롤 위치 기억하기 (0) | 2023.07.10 |