Open lesenelir opened 4 months ago
RSC zero js bundle size ... 浏览器拿到的是 组件在服务端执行后的结果,即 RSC Payload,但拿不到具体的 js bundle。 只有对应的 client component 才会将 js bundle 下载到 浏览器端,并进行执行 js。
RSC 执行和渲染都发生在服务端。 流程:
jsx ---- react 执行 rsc ----> React.ReactNode ---- react server dom 序列化 -----> RSC payload
RSC Payload 会以 Stream 方式,逐行(按行分割数据,只要是 stream 就是按行分割)从服务端发送给客户端;而客户端会逐行进行解析 RSC Payload, 渐进渲染、分块水合。
RSC Payload 中,包含了 client component 的引用, 遇到 RCC 组件时,只输出一个 placeholder 占位符,并指示由 RCC 来填充。React 接受到 RSC Payload 后,下载 client component 的 js bundle, 再在浏览器下执行 js、生成 DOM、水合,最后将渲染结果放在「占位符」处。(RCC 的渲染是在 客户端中执行)
RSC 的一些好处:
rsc payload --> ui ...
由于 rsc 并不会发送 js bundle 到 client , 所以在客户端只有 client component 会进行水合,所以 rsc 应用在 TTI 指标上会好过其他应用。
不同于 Stream HTML,分块渲染和分块水合 虽然能够以 stream 和 「选择水合」的方式进行渲染,对于传统 SSR 来说会有一定优势,但还是会在客户端水合所有的组件。
client component 存在 client boundary , rcc 中不能 import rsc,但 rsc 可以通过 props 传递到 rcc 组件中。
rsc 中可以 import rcc,但是 如果 rsc 传递 props 给 rcc 中会存在 network boundary, props 都需要被序列化,所以这种情况下,不能传递 function 给 rcc 组件。 network boundary 在 page router 中是存在在 getServerSideProps 中,现在 app router 中是存在在 rsc 和 rcc 组件之间。跨网络传递 props 就需要可以被序列化。
client component 尽可能移到组件树的叶子结点处(但很多项目都是 page 页面组件就直接开始设置为 rcc 😅)
这篇文章主要介绍 next app router 的一些相关使用
從 Next.js 13 認識 React Server Components
由于存在 rsc 和 rcc ,它们的执行环境不同,一些 js module 执行时的需要区分地方:server-only 和 client-only 。比如:
export const getData = async () => {
let res = await fetch(xxx, {
headers: {
authorization: process.env.API_KEY
}
})
}
fetch 是在 客户端侧执行,但 process.env 是在 node 服务侧执行,如果在服务端侧执行就不用 fetch 请求,直接从数据库中拿数据。所以这是一种错误的做法。最好找一些 server-only 的一些第三方包来避免这些类似的问题。
关于 data fetching 问题:
nextjs pages router 框架而言,在服务端请求数据是在 getServerSideProps 中请求数据,从 page 层级的组件拿到数据,再一层层 props 到各自组件中,所以在服务端请求数据的层级是 Page Component 级别;而 RSC 是可以将 请求数据的层级粒度到一个组件上。
Nextjs 对 fetch 进行了一次封装,会「快取」「automatic request deduping」,如果是同一个 fetch 请求,则直接回传快取结果值。
Nextjs 有一个 cache 函数,cache(fn),如果 fn 的参数不变,则值一直保持不变。
https://www.plasmic.app/blog/how-react-server-components-work#the-rsc-wire-format