React 17 이하에서, hydrate
는 react-dom/server
로부터 생성된 React 컴포넌트의 HTML 콘텐츠를 브라우저 DOM 노드에 표시할 수 있도록 해줍니다.
hydrate(reactNode, domNode, callback?)
레퍼런스
hydrate(reactNode, domNode, callback?)
React 17 이하에서 hydrate
를 호출하면 React가 서버 환경에서 미리 렌더링한 HTML에 React를 연결(attach)할 수 있습니다.
import { hydrate } from 'react-dom';
hydrate(reactNode, domNode);
React는 domNode
에 있는 HTML에 연결되고, 그 내부의 DOM 관리를 맡습니다. React로 빌드된 앱은 보통 hydrate
를 루트 컴포넌트에서 딱 한 번 실행합니다.
매개변수
-
reactNode
: HTML을 렌더링하기 위해 사용되는 React 노드입니다. React 17의renderToString(<App />)
같은ReactDOM Server
메서드로 렌더링 된<App />
처럼, 일반적으로 JSX 조각 형태입니다. -
domNode
: 서버에서 루트 요소로 렌더링 된 DOM 요소입니다. -
optional:
callback
: 컴포넌트가 hydrate 된 후 호출되는 함수입니다.
반환값
hydrate
는 null을 반환합니다.
주의 사항
hydrate
는 클라이언트에서 렌더링 된 콘텐츠가 서버에서 렌더링 된 콘텐츠와 동일할 것이라고 예상합니다. 텍스트 콘텐츠의 차이 정도는 React가 조정할 수 있긴 하지만, 불일치는 버그로 간주하고 수정해야 합니다.- 개발 모드에서 React는 hydration 중 일어난 불일치에 대해 경고합니다. 불일치하는 경우 어트리뷰트 차이가 조정된다는 보장은 없습니다. 이는 성능상의 이유로 중요한데, 대부분의 앱에서 불일치가 발생하는 경우는 드물기 때문에 모든 마크업의 유효성을 검사하는 데 엄청난 비용이 들기 때문입니다.
- 각 앱에서
hydrate
는 한 번만 실행하세요. 프레임워크를 사용하는 경우 프레임워크가 대신 호출하고 있을 것입니다. - 앱이 서버에서 렌더링 된 HTML 없이 클라이언트에서만 렌더링 되는 경우엔
hydrate()
를 사용할 수 없습니다. 이럴 때는 render()(React 17 이하) 또는 createRoot()(React 18+)를 사용하세요.
사용법
hydrate
로 React 컴포넌트를 서버에서 렌더링 된 브라우저 DOM 노드에 연결하세요.
import { hydrate } from 'react-dom';
hydrate(<App />, document.getElementById('root'));
hydrate()
로 클라이언트에서만 동작하는 (서버 측에서 렌더링 되는 HTML이 없는) 앱을 만들 순 없습니다. 이럴 때는 render()(React 17 이하) 또는 createRoot()(React 18+)를 사용하세요.
서버에서 렌더링 된 HTML Hydrate 하기
React에서 “hydration”은 React가 서버 환경에서 미리 렌더링한 HTML에 연결하는 방식을 말합니다. 클라이언트에서 hydration이 일어나면 React는 서버에서 생성된 마크업에 이벤트 리스너를 연결하고 앱 렌더링을 이어받으려고 합니다.
React로 빌드된 앱에서는 보통 앱이 시작될 때 단 한 번 하나의 루트만 hydate 합니다.
import './styles.css'; import { hydrate } from 'react-dom'; import App from './App.js'; hydrate(<App />, document.getElementById('root'));
대부분의 경우 hydrate
를 다시 호출하거나 다른 곳에서 더 호출할 필요는 없습니다. React는 hydrate
가 호출된 시점부터 애플리케이션의 DOM을 관리합니다. UI를 업데이트해야 한다면 state를 사용하면 됩니다.
hydration에 대한 더 자세한 내용은 hydrateRoot
문서를 참고하세요.
불가피한 hydration 불일치 에러 무시하기
단일 요소의 어트리뷰트나 텍스트 콘텐츠가 서버와 클라이언트 간 다를 수밖에 없는 경우(예: 타임스탬프), hydration 불일치 경고를 무시하도록 처리할 수 있습니다.
hydration 경고를 무시하려면 suppressHydrationWarning={true}
를 추가하세요.
export default function App() { return ( <h1 suppressHydrationWarning={true}> Current Date: {new Date().toLocaleDateString()} </h1> ); }
이 방법은 한 레벨 깊이에서만 작동하며 임시방편일 뿐입니다. 텍스트 콘텐츠가 아닌 이상 React는 조정을 시도하지 않을 것이므로 향후 업데이트가 있을 때까지 일관적이지 않은 상태로 남을 수 있습니다. 남용하지 마세요.
서로 다른 클라이언트 및 서버 콘텐츠 처리하기
서버와 클라이언트에서 의도적으로 다른 것을 렌더링하는 경우, 투 패스 렌더링(two-pass rendering)을 사용해 볼 수 있습니다. isClient
같은 state variable를 선언해 Effect에서 true
로 바꿔 사용하면 됩니다.
import { useState, useEffect } from "react"; export default function App() { const [isClient, setIsClient] = useState(false); useEffect(() => { setIsClient(true); }, []); return ( <h1> {isClient ? 'Is Client' : 'Is Server'} </h1> ); }
이렇게 하면 첫 번째 렌더링 패스(render pass)에서 서버와 같은 콘텐츠를 렌더링하므로 불일치를 피할 수 있으면서도, hydration 직후 추가 렌더링 패스가 동기적으로 발생하도록 할 수 있습니다.