React DOM의 render와 hydrate
next를 사용하던 도중 SSR(Server Side Rendering)에서 사용되는 hydrate
라는 키워드에 대해 공부하고 싶어져서 공부해보았다.
react-dom
은 앱의 최상위 레벨에서 사용하는 DOM과 관련한 메서드와 React 모델 외부로 나갈 수 있는 해결책을 제공한다.
cra로 만든 프로젝트 기준 최상위 레벨인 index.js
에서 사용된다.
render 메소드를 제공해주는 그 패키지이다.
1 | import React from "react"; |
render
1 | ReactDOM.render(element:React$Element<any>,container:Container,callback:?Function,) |
render
는 element
를 container
DOM에 렌더링하고 컴포넌트에 대한 참조(Ref)를 반환한다.
callback
이 제공되면 렌더링되거나 업데이트 된 후에 실행된다.
element
가 이전에 container
내부에 렌더링 되었다면 해당 엘리먼트는 업데이트하고 최신의 React 엘리먼트를 반영하는 데 필요한 DOM만 변경한다.
일전에 공부하였던 diff 알고리즘
과 React fiber
를 통하여 DOM에 변경점만 업데이트 하거나 렌더링하는 함수이다.
코드
ReactDOM에서 render
함수를 볼 수 있다.
동작방식은 다음과 같다.
container
가 DOM 엘리먼트인지 확인하고 아닐경우 에러를 발생시킨다.root 엘리먼트는
_reactRootContainer
속성을 가지고 있다.
또한 container는__reactContainere+$랜덤 문자열
속성도 가지고 있다.
다음 경우 에러를 발생시킨다.container
의__reactRootContainer
속성이undefined
일 경우container
내부에__reactContainerer+$랜덤 문자열
속성이 존재하지 않을 경우
2까지 에러가 발생하지 않았을 경우 DOM 엘리먼트인
container
의sub tree
로 React 엘리먼트인element
를 render한다.
1 | export function render( |
주의사항
공식문서에 나와있는 주의사항은 다음과 같다.
ReactDOM.render()는 처음 호출할 때 기존의 DOM 엘리먼트를 교체하며 이후의 호출은 React의 DOM diffing 알고리즘을 사용하여 더욱 효율적으로 업데이트한다.
ReactDOM.render()는 컨테이너 노드를 수정하지 않고 컨테이너의 하위 노드만 수정하여 자식 노드를 덮어쓸 필요 없이 기존의 DOM 노드에 컴포넌트를 추가할 수 있다.
ReactDOM.render()는 현재 ReactComponent 루트(root) 인스턴스에 대한 참조를 반환한다. 그러나 이 반환 값을 사용하는 것은 피해야한다.
ReactComponent 인스턴스의 참조가 필요하다면 권장하는 해결책은 루트 엘리먼트에 콜백 ref를 붙여야한다.ReactDOM.render()를 사용해 서버에서 렌더링한 컨테이너에 이벤트를 보충할 때는 hydrate()를 사용해야 한다.
hydrate
1 | ReactDOM.hydrate(element:React$Element<any>,container:Container,callback:?Function,) |
위의 render
와 동일하지만 HTML이 ReactDOMServer
로 렌더링 된 후 컨테이너에 이벤트를 보충하기 위해 사용된다.
React는 기존 마크업에 이벤트 리스너를 연결한다.
서버에서 온 정적인 HTML코드에 React 코드들을 렌더링하여 리액트가 관리할 수 있도록 컴포넌트화 하는 함수이다.
SSR을 하는 경우에는 hydrate로 콜백만 붙여야 한다.(고한다.)
코드
마찬가지로 ReactDOM에서 hydrate 코드를 볼 수 있다.
render
와 동작 방식이 똑같다.
다만 render
와 달리legacyRenderSubtreeIntoContainer
함수에서 forceHydrate
가 true이다.
1 | return legacyRenderSubtreeIntoContainer( |
1 | export function hydrate( |