선택적 하이드레이션

Selective hydration

여러 서버 렌더 영역 중 사용자가 먼저 상호작용한 영역의 하이드레이션을 우선합니다.

···
html
<section class="stage"><div class="heading">SELECTIVE HYDRATION <span class="hint">interaction first</span></div><div class="hydration-lanes"><div class="lane" data-lane="feed"><b>FEED</b><span class="meter"><i></i></span><em>waiting</em></div><div class="lane" data-lane="comments"><b>COMMENTS</b><span class="meter"><i></i></span><em>waiting</em></div><div class="lane" data-lane="search"><b>SEARCH</b><span class="meter"><i></i></span><em>waiting</em></div></div><div class="caption" id="hydrate-note">Tap comments: its boundary takes priority</div></section>
css
.stage{width:min(94vw,780px);height:min(88vh,322px);padding:clamp(12px,3vmin,20px);border:1px solid var(--line);border-radius:16px;background:var(--surface);box-shadow:0 12px 36px #0001;display:flex;flex-direction:column;gap:clamp(7px,2vmin,14px);font:500 clamp(12px,3.5vmin,17px)/1.3 var(--font-sans,system-ui,sans-serif);overflow:hidden}.heading{display:flex;justify-content:space-between;align-items:center;gap:8px;font-weight:750;color:var(--accent)}.hint{color:var(--muted);font-size:clamp(12px,3.2vmin,14px);font-weight:500}.caption{margin-top:auto;color:var(--muted);font-size:clamp(12px,3.2vmin,14px)}.row{display:flex;gap:clamp(5px,1.5vmin,12px);align-items:center}.tile{padding:clamp(6px,1.8vmin,13px);border:1px solid var(--line);border-radius:9px;background:var(--bg);text-align:center;min-width:0}.arrow{color:var(--accent);font-weight:800}.stage [data-on]{transition:background .3s,border-color .3s,opacity .3s,transform .3s}.stage .on{border-color:var(--accent);background:color-mix(in srgb,var(--accent) 14%,var(--surface));color:var(--accent)}.hydration-lanes{flex:1;display:flex;flex-direction:column;justify-content:center;gap:clamp(5px,1.8vmin,12px)}.lane{display:grid;grid-template-columns:34% 1fr 24%;align-items:center;gap:8px;padding:5px 8px;border:1px solid var(--line);border-radius:7px;background:var(--bg);font-size:clamp(12px,3vmin,15px)}.lane b{font-size:inherit}.lane em{font-style:normal;color:var(--muted);text-align:right}.meter{height:8px;border-radius:8px;background:var(--line);overflow:hidden}.meter i{display:block;width:0;height:100%;background:var(--accent);transition:width .35s}.lane.active{border-color:var(--accent)}.lane.active .meter i{width:100%}.lane.active em{color:var(--accent)}.stage small,.stage button,.stage .cards b,.stage .phase b,.stage .pair b,.stage .tree-mini b{font-size:clamp(12px,3.2vmin,14px)!important}
js
const lanes=[...document.querySelectorAll(".lane")],note=document.getElementById("hydrate-note");let step=0;function tick(){const active=step===0?[]:step===1?[1]:[1,0,2];lanes.forEach((lane,i)=>{lane.classList.toggle("active",active.includes(i));lane.querySelector("em").textContent=active.includes(i)?"ready":"waiting"});note.textContent=step===0?"Tap comments: its boundary takes priority":step===1?"Comments respond before other regions":"Remaining regions hydrate afterwards";step=(step+1)%3}tick();const timer=setInterval(tick,1050);lanes.forEach((lane,i)=>lane.addEventListener("pointerdown",()=>{clearInterval(timer);step=i===1?1:2;tick()}))

선택적 하이드레이션은 서버 HTML을 한꺼번에 활성화하지 않고 서스펜스 경계별로 나눠 처리합니다. React는 경계의 코드가 준비되면 하이드레이션을 진행하고, 사용자가 아직 활성화되지 않은 영역을 누르면 그 영역을 우선 처리할 수 있습니다.

우선순위 변경은 필요한 코드가 이미 도착한 범위에서 작동합니다. 다운로드되지 않은 기능을 즉시 실행할 수는 없습니다. 데모는 댓글을 누르면 다른 영역보다 먼저 활성화되는 모습을 보여줍니다.

언제 쓰나

서버 렌더 페이지에 여러 대화형 영역이 있고 초기 JavaScript가 순차적으로 준비될 때 유용합니다.

페이지로 열기 ↗