从 "use client" 引出RSC与Next的重新认识
引子
起因是这样的,今天早上在群里看到有个小伙伴发了这样一张截图,并表示疑惑:“我原来觉得我懂RSC,看他们吵这个我又看不懂了。”
因为这种截图,群里产生了激烈的讨论,主要是关于何时使用 "use client",以及有的小伙伴和我一样关于 RSC 产生了些许的疑问。那我们往下看看吧。
use client
在文章看头的截图里,dan 说只有在 server / client 边界时使用 "use client"才是必要的。我们可以浅看下 dan 说的例子,如果不是太懂,可以看看下面我的阐述。
为什么需要使用
借鉴next
官网的原话:
Client Rendering
的好处:
- 交互性:
Client Components
可以使用state
、effects
、和事件监听器,意味着它们可以向用户提供及时反馈并更新UI。 - 浏览器API:
Client Components
可以访问浏览器API,像地理位置或者localStorage
,允许你为特定用例构建UI。
使用时机
我们先看一个nextjs
官网的截图。
注意这句话:use client
被使用在声明一个 Server Component
和 Client Component
模块之间的边界。意味着一个文件中定义了use client
,那么它导入的所有模块,包括子模块都是 Client bundle
,也就表示这些模块不需要再在其中定义use client
,这就是对 dan 说的边界和不需要使用use client
的完美阐述。
重新了解Next
Next
自从13版本后,使用App Router
将内置使用React Server Components
(RSC
)。
Server Components
React 服务器组件允许您编写可以在服务器上渲染和选择性缓存的 UI。在 Next.js 中,渲染工作被路由段进一步分割,以实现流式渲染和部分渲染,并且存在三种不同的服务器渲染策略:
在服务器上进行渲染工作有几个好处,包括:
- 数据获取:服务器组件允许您将数据获取移至更靠近数据源的服务器。这可以通过减少获取渲染所需数据所需的时间以及客户端需要发出的请求数量来提高性能。
- 安全性:服务器组件允许您在服务器上保留敏感数据和逻辑,例如令牌和 API 密钥,而不会有将它们暴露给客户端的风险。
- 缓存:通过在服务器上渲染,可以缓存结果并在后续请求和跨用户中重用。这可以通过减少每个请求上完成的渲染和数据获取量来提高性能并降低成本。
- 捆绑包大小:服务器组件允许您保留较大的依赖项,而这些依赖项以前会影响服务器上的客户端 JavaScript 捆绑包大小。这对于互联网速度较慢或设备功能较弱的用户来说是有益的,因为客户端不必为服务器组件下载、解析和执行任何 JavaScript。
- 初始页面加载和首次内容绘制 (FCP):在服务器上,我们可以生成 HTML 以允许用户立即查看页面,而无需等待客户端下载、解析和执行渲染页面所需的 JavaScript。
- 搜索引擎优化和社交网络共享性:搜索引擎机器人可以使用渲染的 HTML 来索引您的页面,社交网络机器人可以使用渲染的 HTML 来为您的页面生成社交卡预览。
- 流式传输:服务器组件允许您将渲染工作分成多个块,并在准备就绪时将它们流式传输到客户端。这允许用户更早地看到页面的某些部分,而不必等待整个页面在服务器上呈现。
如何渲染
在服务器上,Next.js 使用 React 的 API 来编排渲染。渲染工作被分成多个Chunk:按单独的路线段和 Suspense Boundaries。
每个Chunk都分两步渲染:
- React 将服务器组件呈现为一种特殊的数据格式,称为React 服务器组件有效负载(RSC Payload)。
- Next.js 使用 RSC 有效负载和客户端组件 JavaScript 指令在服务器上呈现HTML 。
然后,在客户端:
- HTML 用于立即显示路线的快速非交互式预览 - 这仅适用于初始页面加载。
- React 服务器组件有效负载用于协调客户端和服务器组件树,并更新 DOM。
- JavaScript 指令用于Hydrate客户端组件并使应用程序具有交互性。
What is the React Server Component Payload (RSC)?
The RSC Payload is a compact binary representation of the rendered React Server Components tree. It's used by React on the client to update the browser's DOM. The RSC Payload contains:
- The rendered result of Server Components
- Placeholders for where Client Components should be rendered and references to their JavaScript files
- Any props passed from a Server Component to a Client Component
Client Components
要使用Client Components
,需要添加use Client
,关于它的使用方法前文已介绍,不再赘述。
这里我之前一直有一个误区,认为Client Components
是在页面返回后才加载其组件UI的,但今天仔细回顾才发现这种想法是错误的。下面将详细介绍。
如何渲染
在 Next.js 中,客户端组件的渲染方式有所不同,具体取决于请求是完整页面加载(对应用程序的初始访问还是浏览器刷新触发的页面重新加载)或后续导航的一部分。
整页加载
为了优化初始页面加载,Next.js 将使用 React 的 API 在服务器上为客户端和服务器组件呈现静态 HTML 预览。这意味着,当用户第一次访问您的应用程序时,他们将立即看到页面的内容,而无需等待客户端下载、解析和执行客户端组件 JavaScript 包。
注意:
这里明确说明了:为both Client and Server Components呈现静态HTML预览,(我理解的是UI会服务器端同服务器组件一同返回,事件那些在客户端加载,因为use client
是给webpack插件做标记用的,类似React.lazy
的效果)。
后续导航
在后续导航中,客户端组件完全在客户端上呈现,而不需要服务器呈现的 HTML。
这意味着客户端组件 JavaScript 包已下载并解析。一旦包准备好,React 将使用 RSC Payload 来协调客户端和服务器组件树,并更新 DOM。