谈谈 React 新出的 Server Components
共 24503字,需浏览 50分钟
·
2020-12-26 13:52
昨天看了 demo,今天翻了翻源码。我们应该从几个维度来“看待” React Server Components:
当前开发遇到了哪些痛点?
这些痛点目前有哪几种解决方案?
Server Components 是怎么解决这些痛点的?
Server Components 是否比这些解决方案更优秀?
Server Components 是某一个或某几个解决方案的升级、颠覆还是互补?
而最常拿来和 Server Components 对比的就是传统的 PHP/ASP 技术和为框架而生的 SSR 技术。React Server Components 这个技术,听起来和 SSR 很像,而代码看起来则和 PHP 很像。很多人认为这是一种倒退,“前端好不容易爬到了山顶,却发现 PHP 已经等待多时”。其实恰恰相反,使用一种“和现有技术类似的”方式来解决某个开发痛点的做法,正是一种先进而优雅的方式。就好比 jsx 和 html 很相似,vue template 和 mustache 很相似,极低的减轻了开发者的学习成本。
虽然表面相似,但是却完全不同。
在 PHP/ASP 时代,页面都是由服务器来渲染。服务器接到请求后,查询数据库然后把数据“塞”到页面里面,最后把生成好的 html 发送给客户端。当用户点击链接后,继续重复上面的步骤。这样用户体验不是很好,每个操作几乎都要刷新页面,服务器处理完之后再返回新的页面。
我们可以概括为:
痛点:用户体验太差(user experience)
原因:页面总是刷新
解决思路:让页面别刷新
方案:使用 ajax
而 Angular/Vue/React 这种单页应用(SPA)则主要是客户端渲染。服务器接到请求后,把 index.html 以及 js/css/img 等发送给浏览器,浏览器负责渲染整个页面。后续用户操作和前面的 php/jquery 一样,通过 ajax 和后端交互。但是和 php 相比,第一次访问时只返回了什么内容都没有的 idnex.html 空页面,没法做 SEO。另一点就是页面需要等到 js/css 和接口都返回之后才能显示出来,首次访问会有白屏。
概括一下:
痛点:首次访问白屏
原因:首次访问只返回了 index.html 页面
解决思路:首次访问时返回渲染完的页面
方案:SSR
SSR 的方式是:首次访问的时候由服务器(通常是 Node.js)来渲染页面,然后把已经渲染好的 html 发送给浏览器。后续的用户操作依然通过 ajax 获取数据,然后在浏览器端渲染组件和页面。
那么能不能让首屏的体验更好呢?
痛点:SSR 首屏还是太慢
原因:服务端渲染是请求的接口太多,导致响应时间太长
解决思路:分块渲染,把已经渲染好的部分尽早的发送到浏览器
方案:bigPipe
我们根据这种思路重新审视一下 React Server Components 解决了什么问题。
在视频的开篇,Dan 就举了一个“鱼与熊掌不可兼得”的例子:
Good:用户体验 Cheap:可维护性 Fast:性能
例子很简单,页面中的三个组件应该如何请求数据?
顶层组件通过 1 个接口 fetch 所有数据,这样请求的时候会变长。用户体验✅ 可维护性❎ 性能❎
顶层组件通过 3 个接口并行 fetch 所有数据:用户体验✅ 可维护性❎ 性能✅
每个组件自行 fetch 数据:用户体验❎ 可维护性✅ 性能✅
面对种种痛点,我们也都有自己的方案。比如:
我们可以通过增加服务器配置来解决,或者优化后端代码来解决。解决思路是让接口响应变快。
使用 graphql 按需查询后端数据。
……
React 团队分析了导致痛点的原因:组件需要反复从服务器请求数据。而 React 团队给出的解决方案是:把组件放到服务器端,这样客户端和服务器端只需要往返一次。和 graphql 的思路很像,但是更加贴近 react 生态,也更加 frontend style。
我截取了视频中的 30 秒,很好的说明了这种理念。
graphql 看似美好,但是落地困难。我使用 Gatsby 开发过几个项目,也做过 React Native 的 Facebook 登录,graphql 是真香。但是我觉得影响 graphql 落地的最大障碍就是 “明明是解决的前端痛点,却非要改造后端”。而把 graphql 做 BFF 来用坑也不少。
而 React Server Components 则完全是按 React 的思维来解决这个问题。甚至可以说是按前端组件化的思维来解决这个问题,这种思想 Vue 也可以实现。
前端发起请求,服务器端组件可以查询 db,可以访问接口 api,…… 而且和 SSR 不同,服务器响应的不是 html,而是一个序列化的“指令”。客户端根据此“指令”集来渲染组件和页面。
(PS:服务器直接返回 html 片段的技术也有了,叫 pjax/turbolinks。我去年和一个团队交流,说他们在做基于 React 组件的 pjax,后来放弃了)
M1:{"id":"./src/SearchField.client.js","chunks":["client5"],"name":""}
M2:{"id":"./src/EditButton.client.js","chunks":["client1"],"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","94",{"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":"./src/SidebarNote.client.js","chunks":["client6"],"name":""}
J4:["$","ul",null,{"className":"notes-list","children":[["$","li","94",{"children":["$","@6",null,{"id":94,"title":"Untitled feng","expandedChildren":["$","p",null,{"className":"sidebar-note-excerpt","children":"feng test"}],"children":["$","header",null,{"className":"sidebar-note-header","children":[["$","strong",null,{"children":"Untitled feng"}],["$","small",null,{"children":"6:21 AM"}]]}]}]}],["$","li","93",{"children":["$","@6",null,{"id":93,"title":"Untitled","expandedChildren":["$","p",null,{"className":"sidebar-note-excerpt","children":"Null"}],"children":["$","header",null,{"className":"sidebar-note-header","children":[["$","strong",null,{"children":"Untitled"}],["$","small",null,{"children":"6:06 AM"}]]}]}]}],["$","li","92",{"children":["$","@6",null,{"id":92,"title":"TEST","expandedChildren":["$","p",null,{"className":"sidebar-note-excerpt","children":"DDD"}],"children":["$","header",null,{"className":"sidebar-note-header","children":[["$","strong",null,{"children":"TEST"}],["$","small",null,{"children":"6:06 AM"}]]}]}]}],["$","li","90",{"children":["$","@6",null,{"id":90,"title":"æµè¯æµè¯","expandedChildren":["$","p",null,{"className":"sidebar-note-excerpt","children":"æµè¯æµè¯æµè¯æµè¯æµè¯æµè¯æµè¯æµè¯æµè¯æµè¯æµè¯æµè¯æµè¯æµè¯"}],"children":["$","header",null,{"className":"sidebar-note-header","children":[["$","strong",null,{"children":"æµè¯æµè¯"}],["$","small",null,{"children":"5:49 AM"}]]}]}]}],["$","li","89",{"children":["$","@6",null,{"id":89,"title":"åµåµåµð±","expandedChildren":["$","p",null,{"className":"sidebar-note-excerpt","children":["$","i",null,{"children":"(No content)"}]}],"children":["$","header",null,{"className":"sidebar-note-header","children":[["$","strong",null,{"children":"åµåµåµð±"}],["$","small",null,{"children":"5:43 AM"}]]}]}]}],["$","li","88",{"children":["$","@6",null,{"id":88,"title":"Untitled","expandedChildren":["$","p",null,{"className":"sidebar-note-excerpt","children":"ï¼ï¼ï¼ï¼"}],"children":["$","header",null,{"className":"sidebar-note-header","children":[["$","strong",null,{"children":"Untitled"}],["$","small",null,{"children":"5:32 AM"}]]}]}]}],["$","li","87",{"children":["$","@6",null,{"id":87,"title":"test03","expandedChildren":["$","p",null,{"className":"sidebar-note-excerpt","children":"hahah hahah ahahha"}],"children":["$","header",null,{"className":"sidebar-note-header","children":[["$","strong",null,{"children":"test03"}],["$","small",null,{"children":"5:32 AM"}]]}]}]}],["$","li","86",{"children":["$","@6",null,{"id":86,"title":"æ±ä¸è¦æ´æ°äº, èåå¦ä¸å¨äº","expandedChildren":["$","p",null,{"className":"sidebar-note-excerpt","children":["$","i",null,{"children":"(No content)"}]}],"children":["$","header",null,{"className":"sidebar-note-header","children":[["$","strong",null,{"children":"æ±ä¸è¦æ´æ°äº, èåå¦ä¸å¨äº"}],["$","small",null,{"children":"5:30 AM"}]]}]}]}],["$","li","84",{"children":["$","@6",null,{"id":84,"title":"Untitled","expandedChildren":["$","p",null,{"className":"sidebar-note-excerpt","children":" 1 2 3 4 5