V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
zzzzzzggggggg
V2EX  ›  程序员

SSR 在左, React Server Component 在右

  •  
  •   zzzzzzggggggg · 2021-01-11 13:55:49 +08:00 · 880 次点击
    这是一个创建于 1194 天前的主题,其中的信息可能已经有所发展或是发生改变。

    各位 v2exer 好,这是我的新文章👇:

    2020 年已经过去了,但是有一项 2020 年的技术提案仍然值得研究,它就是 React Server Component !没错,React 团队又出新活儿了,学不动的同学可以直接看本篇文章😸

    已经有了 SSR,为什么还会有 React Server Component 这种东西出现呢?它们俩的区别是什么呢?

    要解释这些问题,我们先来看看 Web 渲染的发展历程。

    web 渲染发展历程

    远古时期的前端代码,都是夹杂在 Php 、Jsp 、Asp 的代码中,并且整个页面由服务器来查询数据并且填充拼接,最终生成的是一个完整的 HTML 页面,返回给浏览器可以直接去解析展现,到现在有很多网站还是这样的模式,比如下图这种:

    随着时间的发展,这种模式的问题也逐步凸显。

    从用户体验上来说,每次在页面上点击一个 tab 切换,都有可能是返回一个完整的 Html,浏览器会重新刷新一次,这种体验是很难受的,因为有可能你在页面上勾选了一些状态会在刷新之后完全消失掉,这会让人感觉不是在使用一个应用,而是在不同的几个单独页面之间来回切换,使用体验非常不流畅。

    从开发体验上来说,前后端的代码、仓库混在一起,前端工程师急需要独立的来做一些事情来提升开发体验和用户体验,此时 Ajax 技术出现了。

    随着 Ajax 技术的广泛应用以及 Vue 、React 、Angular 等等技术的出现,前端单页应用越来越被前端工程师所接受。此时几乎所有的拉取数据、组装 Html 、渲染页面的工作都放到了前端来做,服务端的职责收敛到 API 请求来执行业务逻辑和获取数据,前后端的职责分明,分别把持网站的两头,中间是 Http 请求把他们串起来。

    但是这种单页面应用的纯前端渲染也带来了一些问题,因为在首次请求的时候,服务器端只会返回一个几乎为空的 Html (如下图),后续的内容数据都靠 Ajax 去动态的获取,如果要请求的数据很多的话,就会产生白屏,并且会有 SEO 问题。而且随着前端工程的膨胀,打包后的代码体积也会越来越大。

    为了解决首次访问白屏问题以及 SEO 问题,大家把目光转向了 SSR (服务端渲染),React 社区推出了 Next.js ,Vue 社区推出了 Nuxt.js ,它们都是在首次访问某页面时,直接在服务器端拼装一个完整的 Html 。

    React Server Component

    单页应用+部分页面 SSR 就是完美的方案吗?肯定不是的。做技术的都知道每种方案只是符合某些条件下的特定场景而已,随着业务复杂度上升以及技术债的堆积,SSR 的问题也凸显出来,如果一个页面请求的接口很多,那么这个页面在服务端就会花费很长的时间才能拼装完成,那么响应时间依然过长。而且搞过 SSR 的同学都知道,这里面踩坑也不少。

    到目前为止,我们已经清晰的知道前端开发的痛点了:

    1. 更好的用户体验:不能一言不合就白屏
    2. 更好的开发体验:组件尽可能的和业务解耦,不要写成一坨,更好维护
    3. 更好的性能:尽可能少的请求接口

    对于权衡这 3 个痛点,React 团队给出的解决办法是 React Server Component,它可以让你:

    1. 在服务端运行 React 组件,并且这些组件永远不会被下载到浏览器中去,这样子就可以减小前端项目的打包体积
    2. 完整的服务端访问能力,比如直接在 React 组件中读取文件、访问数据库,在官方给出的 demo 中也看到了 react-fs 、react-pg 这样的库

    并且它和 SSR 的区别在于:

    1. SSR 返回的是一个 Html,而 React Server Component 返回的是一个 React 可解析的结构。
    2. SSR 返回的页面会让页面重新刷新,丢失掉之前页面上的状态,比如表单选中之类的;而 React Server Component 返回的并不会让页面重新刷新而丢失状态。

    使用场景

    以 React 官方给的介绍视频为例,假如有这么一个常见的业务需求,1 个父组件内套了 2 个子组件,并且每个子组件需要的数据不一样:

    为了尽量的少发请求,我们一般会用 1 个接口去拿到 2 份儿数据:

    但是这样子做的问题是,2 个子组件与父组件耦合太严重,不利于维护,于是我们选择在 2 个子组件内各自请求数据:

    但是这样子做相比上一种做法,多了 2 次接口请求,性能上会受影响,使用 React Server Component 重构来做就会是这样:

    组件的业务数据拉取放在了服务端来做,并且服务端组件不会被打包到前端代码中,对于前端来说,整个网络请求只有一次。

    我的看法

    React 团队提出的这项技术,社区也有过类似的,但这次不同的是它是基于 React 技术栈来做的,所以关注度和接受程度会比其他类似的技术更高一些。

    从前端开发者角度来说,这项技术把 Component 的能力从前端扩展到了后端,以后说不定各大公司会出现前端组件公共服务之类的技术基建,可能会在以后改变现有的前端开发模式。

    总之,值得期待。

    zzzzzzggggggg
        1
    zzzzzzggggggg  
    OP
       2021-01-11 14:27:23 +08:00
    交流技术,没有二维码😸
    shunia
        2
    shunia  
       2021-01-11 15:31:01 +08:00
    原谅我完全没看懂
    shunia
        3
    shunia  
       2021-01-11 15:34:09 +08:00
    mara1
        4
    mara1  
       2021-01-11 15:37:32 +08:00
    谢谢,成功劝退,学不动了, 我会尽快转后端去。
    Kasumi20
        5
    Kasumi20  
       2021-01-11 15:44:25 +08:00
    好 - 便宜 - 快

    居然出现三色图,MJJ
    zzzzzzggggggg
        6
    zzzzzzggggggg  
    OP
       2021-01-11 16:10:44 +08:00
    @shunia 原版看着有点累,感觉他举的例子不太切中痛点。。。
    zzzzzzggggggg
        7
    zzzzzzggggggg  
    OP
       2021-01-11 16:11:38 +08:00
    @mara1 其实还好。。后端也有很多概念
    zzzzzzggggggg
        8
    zzzzzzggggggg  
    OP
       2021-01-11 16:11:45 +08:00
    @Kasumi20 啥?
    shunia
        9
    shunia  
       2021-01-11 18:00:07 +08:00
    我说完全看不懂是因为贴文里太抽象化了:

    ‘SSR 返回的是一个 Html,而 React Server Component 返回的是一个 React 可解析的结构。’
    看完原版:RSC 返回的是可以提供给客户端 React 用来进行 merge 的 tree 数据(看例子是纯文本,类似 reactjs.org 那种套路)

    ‘而 React Server Component 返回的并不会让页面重新刷新而丢失状态。’
    看完原版:因为上一点,所以变化的只是 tree,不涉及数据,也就不涉及状态改变

    ‘组件的业务数据拉取放在了服务端来做,并且服务端组件不会被打包到前端代码中,对于前端来说,整个网络请求只有一次。’
    看完原版:Dan 向来喜欢明晰概念,所以‘不会打包到前端代码中’的实现包含了他的核心概念:服务器端组件,客户端组件,共享组件。以此来区分和进行实现。然后就能理解到其实它是做了很细致的划分并且由使用者来保证如何不对前端的打包产生影响的。
    并且‘整个网络请求只有一次’不太严谨。原版描述的逻辑是目前使用的 http chunk 来实现分段数据加载,我后面有看 RFC 理解到它一个例子里的那种组件,是有可能产生多个 chunk 数据段的。而且并不限于 http/1.1,websockets 和 http2 都是有可能使用的。

    另外原版还有一些有意思的点:
    1. 比如 search 功能,既展示了 RSC 使用服务器端资源的例子,也展示了( RFC 里有描述) http chunk 传输数据的特性实际跑起来是什么样子;
    2. RSC 返回的是 tree 用来 render 的数据,感觉可以理解为通过服务器来触发 reconcile,甚至还能按需加载组件,这是我个人觉得很厉害的一个点;
    3. Shared Component,也就是共享组件的存在。当服务器端组件使用 SC 的时候,SC 不会传输到客户端。但是如果客户端组件使用了 SC,RSC 可以利用 2 描述的能力,通过 stream 把这个组件和该组件所需要包含的服务器端数据动态传输到客户端;

    另外 RFC 里有写到一点是:会加重学习的负担,我觉得真的是说的太对了。。。

    RFC: https://github.com/josephsavona/rfcs/blob/server-components/text/0000-server-components.md
    zzzzzzggggggg
        10
    zzzzzzggggggg  
    OP
       2021-01-11 19:30:04 +08:00
    @shunia 老哥看的真仔细👍,不得不说,这些提案确实是加重了学习负担,具体落地还得看以后的发展和公司业务,不然就只是停留在研究阶段
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2568 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 01:26 · PVG 09:26 · LAX 18:26 · JFK 21:26
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.