怎么理解 React Server Component 和 Next.js 的关系

最近Next.js v14发布,发布会的各种梗图刷爆了国外前端社区 。

怎么理解 React Server Component 和 Next.js 的关系

文章插图
Next.js的诸多特性(比如Server Action、App Router) , 都是在RSC(React Server Component)基础上衍生出的 。
从名字可以看出,RSC是React的特性 。那么 , 该怎么理解RSC和Next.js的关系呢?
React团队的宿愿对于前端框架的开发范式,有三个重要衡量因素:
  • 用户体验
  • 维护成本
  • 性能
但是,通常很难做到三者兼顾(具体原因本文不细究,感兴趣的同学可以看data-fetching-with-react-server-components[1] 。
简单来说 , 在前端开发中,「IO瓶颈」是影响内容渲染速度的重要因素(可以简单理解为,前端需要等待请求返回数据后,再根据数据渲染内容,这期间延迟的时间就是「IO瓶颈」) 。
但是 , 前端框架能够掌控的范围局限在前端 , 所以无法对「IO瓶颈」做出极致优化 , 只能在三个因素中做出取舍(比如考虑用户体验与性能时 , 代码维护成本就高) 。
React团队为了同时兼顾三者 , 需要对服务端拥有更多掌控 。这就是RSC诞生的初衷 。
但是 , 大部分React的受众只是把React当作前端view库,并不会直接使用RSC相关功能,所以React团队选择和Next.js团队合作,落地RSC 。
此时我们发现 , React有三类受众:
  1. 普通前端开发者,用稳定的React做业务开发
  2. 其他合作团队(比如Next.js团队),React团队为他们提供API支持
  3. 喜欢尝鲜的开发者/团队,愿意尝试那些可能出现在未来版本中的特性(通常还不稳定)
React团队针对这三类受众,制定了三条版本迭代路径:
  • Latest路径
  • Canary路径
  1. Experimental路径
我们正常通过npm i react下载的React包就是「Latest路径」的打包产物 。
通过npm update react@canary可以替换为canary包,RSC相关的功能就属于canary包 。
怎么理解 React Server Component 和 Next.js 的关系

文章插图
同理,通过npm update react@xperimental可以替换experimental包 。
脱离Next.js使用RSC在Next.js的App Router模式,所有组件默认为服务端组件(即在服务端render的组件),只有当组件所在文件顶部标记了'use client'指令时,该组件是客户端组件(即在前端render的组件) 。
怎么理解 React Server Component 和 Next.js 的关系

文章插图
比如下面就是个客户端组件:
'use client'import {useState} from 'react';function Cpn() {const [num, update] = useState(0);// ...省略}实际上 , 这并不是Next.js自己的定义,而是RSC中的规范 。在React文档中 , 我们可以看到'use client'与'use server'规范的定义,其中:
  • 'use client'用于标记客户端组件(在服务端,默认所有组件都是服务端组件,所以客户端组件需要专门标记) 。
  • 'use server'用于标记前端的某个函数为Server Action(可以在前端执行的服务端逻辑) 。

怎么理解 React Server Component 和 Next.js 的关系

文章插图
既然是规范,那就需要落地 。在Next.js中,规范的落地都被收敛到Next.js框架内部实现了 。如果要脱离Next.js使用RSC , 就需要我们自己落地规范 。
RSC规范的落地包括三部分:
  • 服务端编译时
  • 服务端运行时
  • 客户端运行时
这三者都被收敛到react-server-dom-webpack[2]包中 。
接下来我们简单讲下这三部分的作用 。
服务端编译时通过react-server-dom-webpack/plugin名字中的webpack、plugin字样能看出 , 这是个webpack插件 , 配置类似如下:
const ReactServerWebpackPlugin = require("react-server-dom-webpack/plugin");const config = {// ...省略其他配置plugins: [new ReactServerWebpackPlugin({ isServer: false }),],}


推荐阅读