문서를 읽었지만 React 16 hydrate()
과 의 차이점을 실제로 이해하지 못했습니다 render()
.
hydrate()
SSR과 클라이언트 측 렌더링을 결합하는 데 사용된다는 것을 알고 있습니다.
누군가가 수분 공급이 무엇인지 설명하고 ReactDOM의 차이점은 무엇입니까?
답변:
로부터 ReactDOMServer의 문서 (강조 광산) :
ReactDOM.hydrate()
이 서버 렌더링 마크 업이 이미있는 노드에서 호출 하는 경우 React는이를 보존하고 이벤트 핸들러 만 연결 하므로 매우 우수한 첫로드 경험을 할 수 있습니다.
굵게 표시된 텍스트가 주요 차이점입니다. render
초기 DOM과 현재 DOM 사이에 차이가있는 경우 노드를 변경할 수 있습니다. hydrate
이벤트 핸들러 만 첨부합니다.
로부터 도입하는 것이 Github의 문제 hydrate
별도의 API로 :
이것이 초기 DOM 인 경우 :
<div id="container">
<div class="spinner">Loading...</div>
</div>
그리고 전화 :
ReactDOM.render(
<div class="myapp">
<span>App</span>
</div>,
document.getElementById('container')
)
클라이언트 측 전용 렌더링 (수화 아님)을 수행하려고합니다. 그런 다음 당신은
<div id="container">
<div class="spinner">
<span>App</span>
</div>
</div>
속성을 패치하지 않기 때문입니다.
그들이 속성을 패치하지 않은 이유는
... 이것은 정상적인 수화 모드에서 수화하는 데 정말 느리고 비 SSR 트리로의 초기 렌더링 속도를 늦 춥니 다.
class="spinner"
이 <div>
요소 에있는 그대로 유지되는 이유 입니다.
하이드레이트는 SSR (Server side Rendering)의 경우 기본적으로 사용됩니다. SSR은 서버에서 제공되는 스켈레톤 또는 HTML 마크 업을 제공하므로 페이지가 처음로드 될 때 비어 있지 않고 검색 엔진 봇이 SEO (SSR 사용 사례)에 대해 색인을 생성 할 수 있습니다. 따라서 hydrate는 JS를 페이지 또는 SSR이 적용되는 노드에 추가합니다. 페이지가 사용자가 수행 한 이벤트에 응답하도록합니다.
Render는 클라이언트 측 브라우저에서 컴포넌트를 렌더링하는 데 사용됩니다. 하이드레이트를 render로 바꾸려고하면 렌더링이 더 이상 사용되지 않으며 SSR의 경우 사용할 수 없다는 경고가 표시됩니다. 수화물에 비해 느리기 때문에 제거되었습니다.
나는.의 사용에 대해 위에서 말한 것에 추가 할 특정 사항이 hydrate
없지만 그것에 대해 배우려고 노력하면서 약간의 예를 모았으므로 여기에 도움이되는 사람을위한 작업이 있습니다.
를 사용하는 페이지 ReactDOM.hydrate
와 ReactDOM.render
. <script>
태그 로로드되는 JSX로 작성된 일부 반응 구성 요소에 의존하며 , hydrate
과 (와) 의 차이를 설명하기 위해 서버에 의해 인위적으로 지연됩니다 render
.
페이지를 생성하고 서버를 실행 한 후에 127.0.0.1
는 헤더 수화물 , 버튼 및 두 개의 링크 로 이동하여 표시 됩니다. 버튼을 클릭 할 수 있지만 아무 일도 일어나지 않습니다. 잠시 후 문서로드가 완료되고 버튼이 클릭 수를 계산하기 시작합니다. 그런 다음 "렌더링"링크를 클릭합니다. 이제 내가 표시된 페이지에는 헤더 렌더링 과 두 개의 링크가 있지만 버튼은 없습니다. 잠시 후 버튼이 나타나고 즉시 반응합니다.
"hydrate"페이지에서는 필요한 모든 html이 페이지와 함께 제공되기 때문에 모든 마크 업이 즉시 렌더링됩니다. 아직 연결된 콜백이 없기 때문에 버튼이 응답하지 않습니다. components.js
로드가 완료 되면 에서 load
이벤트가 발생 window
하고 콜백이와 연결됩니다 hydrate
.
'렌더링'페이지에서 버튼 마크 업은 페이지와 함께 제공되지 않고에 의해서만 삽입 ReactDOM.render
되므로 즉시 표시되지 않습니다. 마지막으로로드되는 스크립트에 의해 페이지의 모양이 어떻게 부조리하게 변경되는지 확인하십시오.
다음은 내가 사용중인 사용자 지정 반응 구성 요소입니다. 정적으로 구성 요소를 렌더링하는 데 반응하는 노드의 서버에서 사용되며 페이지에서 사용하기 위해 서버에서 동적으로로드됩니다 ( 파일 시작 부분에서 exports
및 React
개체를 확인하는 목적 임 ).
// components.jsx
var exports = typeof(exports) == 'object' ? exports : {};
var React = typeof(React) == 'object' ? React : require('react');
function MyButton(props) {
[click, setClick] = React.useState(0);
function handleClick() { setClick(click + 1); }
return (
<button onClick={handleClick}>Clicked: {click}</button>
);
}
exports.MyButton = MyButton;
서버에 필요한 모든 페이지를 생성하는 데 사용되는 스크립트입니다. 먼저 babel을 사용하여 components.jsx를 javascript로 변환 한 다음 이러한 구성 요소를 React 및 ReactDOMServer와 함께 사용하여 실제 페이지를 만듭니다. 이러한 페이지는 다음과 같이 getPage
파일에서 내 보낸 기능으로 생성됩니다 pageTemplate.js
.
// genScript.js
let babel = require('@babel/core');
let fs = require('fs');
let ReactDOMServer = require('react-dom/server');
let React = require('react');
let pageTemplate = require('./pageTemplate.js');
script = babel.transformFileSync(
'components.jsx',
{presets : [['@babel/react']]}
);
fs.writeFileSync('components.js',script.code);
let components = require('./components.js');
hydrateHTML = pageTemplate.getPage(
'MyButton',
ReactDOMServer.renderToString(React.createElement(components.MyButton)),
'hydrate'
);
renderHTML = pageTemplate.getPage(
'MyButton',
'',
'render'
);
fs.writeFileSync('hydrate.html',hydrateHTML);
fs.writeFileSync('render.html',renderHTML);
이 파일은 getPage
이전에 언급 한 기능 만 내 보냅니다 .
// pageTemplate.js
exports.getPage = function(
reactElementTag,
reactElementString,
reactDOMMethod
) {
return `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js" defer></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" defer></script>
<script src="./components.js" defer></script>
</head>
<body>
<h1>${ reactDOMMethod }</h1>
<div id="react-root">${ reactElementString }</div>
<a href="hydrate.html">hydrate</a>
<a href="render.html">render</a>
</body>
<script>
window.addEventListener('load', (e) => {
ReactDOM.${ reactDOMMethod }(
React.createElement(${ reactElementTag }),
document.getElementById('react-root')
);
});
</script>
</html>
`;
}
마지막으로 실제 서버
// server.js
let http = require('http');
let fs = require('fs');
let renderPage = fs.readFileSync('render.html');
let hydratePage = fs.readFileSync('hydrate.html');
let componentsSource = fs.readFileSync('components.js');
http.createServer((req, res) => {
if (req.url == '/components.js') {
// artificial delay
setTimeout(() => {
res.setHeader('Content-Type','text/javascript');
res.end(componentsSource);
}, 2000);
} else if (req.url == '/render.html') {
res.end(renderPage);
} else {
res.end(hydratePage);
}
}).listen(80,'127.0.0.1');
위에 추가로 ...
ReactDOM.hydrate()
와 동일 render()
하지만 ReactDOMServer에서 HTML 콘텐츠를 렌더링 한 컨테이너 를 수화 (이벤트 리스너 첨부)하는 데 사용됩니다 . React는 이벤트 리스너를 기존 마크 업에 연결하려고합니다 .
서버 렌더링 컨테이너를 수화하기 위해 ReactDOM.render ()를 사용하는 것은 속도가 느려서 더 이상 사용되지 않으며 React 17 에서 제거 되므로 hydrate()
대신 사용하십시오.