리믹스와 리액트 서버 컴포넌트의 관계를 알아봅니다.
원문 링크입니다 : https://remix.run/blog/react-server-components
리액트 서버 컴포넌트는요?
UX에의 집착
1. Render-Fetch Waterfalls(렌더링 시 가져오기)
JavaScript 번들이 로드 및 컴포넌트가 렌더링된 후 브라우저에서 컴포넌트 내부의 데이터를 가져오는 것을 말합니다.
번들 로드, 렌더링 뒤에 데이터 가져오기를 시작한 후, 동일한 작업을 수행하는 하위 컴포넌트들을 렌더링하기 때문에 이를 "폭포"라고 부릅니다.
모듈 로드 → 렌더(스피너) → 가져오기 → 자식 렌더링(더 많은 스피너) → 자식 가져오기 → etc...
스피너를 렌더링하고 표시하는 것은 각각 폭포수의 각 단계입니다.
우리 홈페이지(take a scroll down our home page)를 아래로 스크롤하여 이 데이터 로드 방법이 UI에 미치는 영향을 확인하십시오.
이러한 리소스를 UI 계층 구조에 연결하여 인공적인 데이터 및 모듈 계층 구조를 생성합니다.
렌더링할 때까지 무엇을 가져올지 모르며 부모의 데이터를 가져올 때까지 렌더링할 수 없습니다!
이는 UI에 "버벅거림"을 생성하고 상위 뷰가 이미 렌더링된 후 하위 뷰가가 페이지에 팝업될 때
2. Fetch, Then Render(가져온 다음 렌더링)
3.Render As You Fetch(렌더링 하면서 가져오기)
리액트 팀의 데모를 리믹스 버전으로 변경해 보았습니다.
RSC는 아직 실험적 API에 불과하고 이것은 장난감 앱에 불과하지만
초기 페이지 로드에서 Remix가 RSC보다 두 배 이상 빠르다는 사실에 놀랐습니다
네트워크 탭을 보면 RSC가 요청의 계단식 폭포를 생성하는 동안
Remix가 리소스를 병렬로 로드하는 방법을 볼 수 있습니다.
코드를 가져오고, 렌더링하고, 서버 컴포넌트를 가져오고, 렌더링합니다. 이 UI에는 중첩 구조도 없습니다.
Remix가 RSC를 훨씬 능가하는 것이 더욱 놀랍습니다.
중첩된 UI를 로드하는 것은 Remix가 RSC보다 더 빛나는 곳입니다. (렌더링 폭포수 때문)
하지만 저는 React 팀의 데모는 초기 서버 렌더링 중에 응답을 스트리밍하는 기능인 SSR Streaming.
즉, React Server Components의 킬러 기능을 실제로 활용하지 않는다는 것도 알고 있습니다.
스트리밍 렌더링 없이 RSC는 단지 컴포넌트 내부에서 데이터를 가져오는 하나의 방법일 뿐입니다.
SSR Streaming, Next.js Demo
Remix vs React Server Components Streaming + Next.js
다시 , Remix는 HTTP 캐싱 없이도 RSC 및 Next.js보다 2배 이상 빠릅니다.
(실제 HN에는 사용자 데이터가 캐싱되어 있으므로 요청이 날아가지 않습니다).
또한 Remix 버전에는 스피너가 표시되지 않았으며 콘텐츠 레이아웃 시프트도 없었습니다.
또한 여기에도 중첩된 UI가 없지만
Remix는 여전히 Next.js + RSC + SSR 스트리밍보다 2배 빠르게 로드됩니다. (stale-while-revalidate 캐싱의 경우 5배).
Remix는 RSC의 이점을 모두 누릴 수 있습니다.
git mv routes/posts.tsx routes/posts.server.tsx
그러나 우리는 RSC가 네트워크 탭에서 만드는 절충안과 관련하여 상당한 우려를 가지고 있습니다.
제로 사이즈 번들 vs 무한 크기 번들
두번째는 준비된 브라우저 캐시 덕택에 16배였습니다.
스트리밍 렌더링 외 React Server Components의 또 다른 강력한 기능 중 하나는 "Zero-Bundle"입니다.
이 아이디어는 속도를 높이기 위해 초기 페이지 로드에서 더 적게 전송하는 것입니다.
(이 데모에서는 이전에 그렇지 않음을 보았습니다). 아이디어는 다음과 같습니다.
리믹스가 아니라 리액트 서버 컴포넌트 입니다.
- 브라우저는 서버 컴포넌트를 렌더링하는 템플릿이 포함된 JavaScript 번들을 로드할 필요가 없습니다.
- 또한 이미 마크업에서 반복되는 JSON으로 가득 찬 일반적인 React SSR 인라인 수화 <script>에 대한 필요성을 제거합니다.
- 이 사이트(https://remix.run/)는 리믹스로 개발되어 있으므로, 위 설명처럼 인라인 <script>로 가득차 있습니다.
M1:{"id":22,"chunks":[2],"name":""}
M2:{"id":20,"chunks":[0],"name":""}
S3:"react.suspense"
J0:["$","div",null,{"className":"main","children":[["$","section",null,{"className":"col sidebar","children":[["$","section",null,{"className":"sidebar-header","children":[["$","img",null,{"className":"logo","src":"logo.svg","width":"22px","height":"20px","alt":"","role":"presentation"}],["$","strong",null,{"children":"React Notes"}]]}],["$","section",null,{"className":"sidebar-menu","role":"menubar","children":[["$","@1",null,{}],["$","@2",null,{"noteId":null,"children":"New"}]]}],["$","nav",null,{"children":["$","$3",null,{"fallback":["$","div",null,{"children":["$","ul",null,{"className":"notes-list skeleton-container","children":[["$","li",null,{"className":"v-stack","children":["$","div",null,{"className":"sidebar-note-list-item skeleton","style":{"height":"5em"}}]}],["$","li",null,{"className":"v-stack","children":["$","div",null,{"className":"sidebar-note-list-item skeleton","style":{"height":"5em"}}]}],["$","li",null,{"className":"v-stack","children":["$","div",null,{"className":"sidebar-note-list-item skeleton","style":{"height":"5em"}}]}]]}]}],"children":"@4"}]}]]}],["$","section","3",{"className":"col note-viewer","children":["$","$3",null,{"fallback":["$","div",null,{"className":"note skeleton-container","role":"progressbar","aria-busy":"true","children":[["$","div",null,{"className":"note-header","children":[["$","div",null,{"className":"note-title skeleton","style":{"height":"3rem","width":"65%","marginInline":"12px 1em"}}],["$","div",null,{"className":"skeleton skeleton--button","style":{"width":"8em","height":"2.5em"}}]]}],["$","div",null,{"className":"note-preview","children":[["$","div",null,{"className":"skeleton v-stack","style":{"height":"1.5em"}}],["$","div",null,{"className":"skeleton v-stack","style":{"height":"1.5em"}}],["$","div",null,{"className":"skeleton v-stack","style":{"height":"1.5em"}}],["$","div",null,{"className":"skeleton v-stack","style":{"height":"1.5em"}}],["$","div",null,{"className":"skeleton v-stack","style":{"height":"1.5em"}}]]}]]}],"children":"@5"}]}]]}]
M6:{"id":21,"chunks":[3],"name":""}
J4:["$","ul",null,{"className":"notes-list","children":[["$","li","1",{"children":["$","@6",null,{"id":1,"title":"Meeting Notes","expandedChildren":["$","p",null,{"className":"sidebar-note-excerpt","children":"This is an example note. It contains Markdown!"}],"children":["$","header",null,{"className":"sidebar-note-header","children":[["$","strong",null,{"children":"Meeting Notes"}],["$","small",null,{"children":"12/30/20"}]]}]}]}],["$","li","2",{"children":["$","@6",null,{"id":2,"title":"A note with a very long title because sometimes you need more words","expandedChildren":["$","p",null,{"className":"sidebar-note-excerpt","children":"You can write all kinds of amazing notes in this app! These note live on the server in the notes..."}],"children":["$","header",null,{"className":"sidebar-note-header","children":[["$","strong",null,{"children":"A note with a very long title because sometimes you need more words"}],["$","small",null,{"children":"12/30/20"}]]}]}]}],["$","li","3",{"children":["$","@6",null,{"id":3,"title":"I wrote this note toda","expandedChildren":["$","p",null,{"className":"sidebar-note-excerpt","children":"It was an excellent note."}],"children":["$","header",null,{"className":"sidebar-note-header","children":[["$","strong",null,{"children":"I wrote this note toda"}],["$","small",null,{"children":"5:59 PM"}]]}]}]}]]}]
J5:["$","div",null,{"className":"note","children":[["$","div",null,{"className":"note-header","children":[["$","h1",null,{"className":"note-title","children":"I wrote this note toda"}],["$","div",null,{"className":"note-menu","role":"menubar","children":[["$","small",null,{"className":"note-updated-at","role":"status","children":["Last updated on ","3 Dec 2021 at 5:59 PM"]}],["$","@2",null,{"noteId":3,"children":"Edit"}]]}]]}],["$","div",null,{"className":"note-preview","children":["$","div",null,{"className":"text-with-markdown","dangerouslySetInnerHTML":{"__html":"<p>It was an excellent note.</p>\n"}}]}]]}]
import{a as i,c as a,d as p}from"/build/_shared/chunk-CDZR6LSD.js";import{a as m}from"/build/_shared/chunk-DQ7ZO7ZN.js";import"/build/_shared/chunk-XXRJHXMM.js";import{i as d}from"/build/_shared/chunk-2FSL4QX2.js";import{b as l,e as t,f as e}from"/build/_shared/chunk-AKSB5QXU.js";e();e();e();var f=l(p());function r(){let{id:n,title:s,body:u,updatedAt:o}=d();return o=new Date(o),t.createElement("div",{className:"note"},t.createElement("div",{className:"note-header"},t.createElement("h1",{className:"note-title"},s),t.createElement("div",{className:"note-menu",role:"menubar"},t.createElement("small",{className:"note-updated-at",role:"status"},"Last updated on ",i(o,"d MMM yyyy 'at' h:mm bb")),t.createElement(a,{noteId:n},"Edit"))),t.createElement(m,{body:u}))}export{r as default};
import{a as d}from"/build/_shared/chunk-XXRJHXMM.js";import{b as i,e as t,f as e}from"/build/_shared/chunk-AKSB5QXU.js";e();e();var n=i(d());function o({text:r}){return t.createElement("div",{className:"text-with-markdown",dangerouslySetInnerHTML:{__html:(0,n.default)(r)}})}function a({body:r}){return t.createElement("div",{className:"note-preview"},t.createElement(o,{text:r}))}export{a};
{"id": 1, "createdAt": "2020-12-30T10:13:29.023Z", "updatedAt":
"2020-12-30T10:13:29.023Z", "title": "Meeting Notes", "body": "This is an
example note. It contains **Markdown**!"}
우리의 교훈
Live Demos and Source Code
Hacker News Demos:
Hacker News Source Code:
Notes App Demos:
Notes App Source Code:
'FrontEnd' 카테고리의 다른 글
Rxjs 시작하기 (0) | 2022.10.08 |
---|---|
리믹스와 엣지 컴퓨팅[Remix and “The Edge”] (0) | 2022.10.08 |
Remix의 데이터 플로우[Data Flow in Remix] (0) | 2022.10.07 |
Vue.js plugin(플러그인) 만들어보기 (0) | 2022.10.07 |
Vue.js 커스텀 Directive 만들어보기 (0) | 2022.10.07 |