当前位置: 首页 > 科技观察

什么是ReactRFC服务器组件以及它们的用途是什么?

时间:2023-03-14 12:59:32 科技观察

12月21日,React团队宣布了一项新提案,服务器组件。与此提案一起,还有一小时的视频解释[1]、可运行的Demo[2]和详细的介绍。可见React团队对这个提案的重视程度。本文将从以下几个方面进行讲解:什么是ServerComponents?服务器组件解决什么问题?一句话介绍什么是ServerComponent:ServerComponents就是运行在服务端的React组件。嗯?这和服务器端渲染(SSR)有什么区别?与SSR相比,组件在服务端渲染成填充内容的HTML字符串,在客户端水化后使用。ServerComponents更像是我们写在客户端的普通组件,只是他的运行环境是服务器端。我们可以按照功能来划分组件:提供数据的容器组件渲染数据并提供数据交互的交互组件比如Note组件就是一个容器组件,负责请求和缓存数据。NoteEditor是一个交互式组件,它呈现笔记数据并执行用户交互。functionNote(props){const[note,setNote]=useState(null);useEffect(()=>{fetchNote(props.id).then(noteData=>{setNote(noteData);});},[props.id]);if(note==null){return"Loading";}else{return}}如示例中所述,我们可以在useEffect中发起请求,并将返回的数据保存在状态。这种“请求-渲染”的模式会遇到一个叫做瀑布的问题:就像一段瀑布流下来一样,NoteEditor需要等待Note请求成功后才能开始渲染。交互组件依赖的数据源越多,瀑布问题就越明显。理论上,如果React足够聪明,它可以在服务端执行容器组件的渲染逻辑,在客户端执行交互组件的渲染逻辑。按照这个概念,完全在客户端渲染的组件树是这样的:可以拆分为运行在服务端的容器组件和运行在客户端的交互组件。其中,运行在服务器端的容器组件就是ServerComponent。ServerComponent的含义既然ServerComponent运行在服务器端,自然更接近于各种IO(请求数据库、读取文件、缓存...)。上面的例子可以直接从数据库中获取笔记数据,同时使用Suspense进行同步写入。functionNote(props){constnote=db.notes.get(props.id);if(note==null){return"Loading";}return}自然更接近于任何其他数据后端源只需要简单的通过React提供的API进行封装,使其支持Suspense,然后就可以连接到ServerComponent。自然更靠近后端。解决瀑布流和SSR传输的HTML字符串的区别。ServerComponent会将Note组件及其IO请求的数据序列化成类似JSX的数据结构,以流的形式传递给前端:客户端在运行时直接获取填充数据的流,并执行流借助ConcurrentMode样式渲染。0打包体积假设我们开发一个MD编辑器。服务器传给前端的MD格式的字符串。我们需要在前端引入一个将MD解析为HTML字符串的库。这个库有206k。importmarkedfrom'marked';//35.9K(11.2Kgzipped)importsanitizeHtmlfrom'sanitize-html';//206K(63.3Kgzipped)functionNoteWithMarkdown({text}){consthtml=sanitizeHtml(marked(text));return(/*render*/);}如何通过ServerComponent解决这个问题呢?只需将NoteWithMarkdown标记为ServerComponent,在服务端执行导入解析MD的逻辑即可。ServerComponent不会增加前端项目的打包体积。在这个例子中,我们减少了前端206K的打包大小(gzipped63.3K)和一次解析MD的时间。自动代码拆分允许使用React.lazy动态导入组件。以前,这需要我们在切换组件/路由时手动完成。在ServerComponent中,这一切都是自动完成的。在上面的动画中,左边的列表是ServerComponent。当点击卡片时,会动态加载组件对应的数据。更好的提前(AOT)优化Vue是一个使用模板语言的框架。模板语言固定的写法使其能够在编译时优化模板内容。由于JSX只是JS的语法糖,React很难在编译时进行优化。ServerComponent对组件进行了更多限制(不能使用useState、useEffect...)。这些限制从侧面为AOT提供了更多的优化线索。ServerComponent的使用下面通过重写一个记事本组件来说明ServerComponent的使用:fetchData(id);返回(

{note.title}

{note.body}
{isEditing?:null}
);}Note组件主要作用是根据props传入的id请求对应的note数据。NoteEditor用于显示和修改注释。fetchData方法用于获取数据,数据的加载状态由组件外部的Suspense完成。可以看出交互部分是由NoteEditor完成的,Note的主要功能是获取和传递数据。接下来我们把Note变成ServerComponent。//注意🙋//Note.server.js-ServerComponent//注意🙋importdbfrom'db.server';//注意🙋importNoteEditorfrom'./NoteEditor.client';functionNote(props){const{id,isEditing}=props;constnote=db.posts.get(id);return(

{note.title}

{note.body}
{isEditing?:null}
);}有3个变化需要注意,我们依次理解:将Note.js的文件名改为Note.server.js的意思这是服务器组件。note.server.js运行在服务端,客户端我们不需要fetchData方法,直接访问数据库即可,所以这里调用db.server提供的方法NoteEditor用于显示和修改笔记.这是由客户端用户的交互控制的,因此将文件名更改为NoteEditor.client意味着这是一个客户端组件。摘要太阳底下并无新鲜事。早期的前端交互很简单,只是作为服务端的View层。随着前端交互变得越来越复杂,出现了以前端框架为主导的客户端渲染(CSR)。为了解决首屏渲染速度和SEO问题,服务器端渲染(SSR)出现了,它回到了View层的起点,但是控制的粒度更细了。ServerComponent提案的出现表明了React的长期目标:将View层的控制细化到组件级别。为什么是“长期目标”?ServerComponent实现的主要前提是ConcurrentMode生产环境稳定。让我们一起期待2021年。参考[1]视频讲解:https://www.youtube.com/watch?v=TQQPAU21ZUw[2]Demo:https://github.com/pomber/server-components-demo/