新聞中心
大家好,我卡頌。

芮城網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)!從網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、響應(yīng)式網(wǎng)站開發(fā)等網(wǎng)站項目制作,到程序開發(fā),運(yùn)營維護(hù)。創(chuàng)新互聯(lián)自2013年起到現(xiàn)在10年的時間,我們擁有了豐富的建站經(jīng)驗和運(yùn)維經(jīng)驗,來保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)。
最近Next.js v14發(fā)布,發(fā)布會的各種梗圖刷爆了國外前端社區(qū)。
Next.js的諸多特性(比如Server Action、App Router),都是在RSC(React Server Component)基礎(chǔ)上衍生出的。
從名字可以看出,RSC是React的特性。那么,該怎么理解RSC和Next.js的關(guān)系呢?
React團(tuán)隊的宿愿
對于前端框架的開發(fā)范式,有三個重要衡量因素:
- 用戶體驗
- 維護(hù)成本
- 性能
但是,通常很難做到三者兼顧(具體原因本文不細(xì)究,感興趣的同學(xué)可以看data-fetching-with-react-server-components[1]。
簡單來說,在前端開發(fā)中,「IO瓶頸」是影響內(nèi)容渲染速度的重要因素(可以簡單理解為,前端需要等待請求返回數(shù)據(jù)后,再根據(jù)數(shù)據(jù)渲染內(nèi)容,這期間延遲的時間就是「IO瓶頸」)。
但是,前端框架能夠掌控的范圍局限在前端,所以無法對「IO瓶頸」做出極致優(yōu)化,只能在三個因素中做出取舍(比如考慮用戶體驗與性能時,代碼維護(hù)成本就高)。
React團(tuán)隊為了同時兼顧三者,需要對服務(wù)端擁有更多掌控。這就是RSC誕生的初衷。
但是,大部分React的受眾只是把React當(dāng)作前端view庫,并不會直接使用RSC相關(guān)功能,所以React團(tuán)隊選擇和Next.js團(tuán)隊合作,落地RSC。
此時我們發(fā)現(xiàn),React有三類受眾:
- 普通前端開發(fā)者,用穩(wěn)定的React做業(yè)務(wù)開發(fā)
- 其他合作團(tuán)隊(比如Next.js團(tuán)隊),React團(tuán)隊為他們提供API支持
- 喜歡嘗鮮的開發(fā)者/團(tuán)隊,愿意嘗試那些可能出現(xiàn)在未來版本中的特性(通常還不穩(wěn)定)
React團(tuán)隊針對這三類受眾,制定了三條版本迭代路徑:
- Latest路徑
- Canary路徑
- Experimental路徑
我們正常通過npm i react下載的React包就是「Latest路徑」的打包產(chǎn)物。
通過npm update react@canary可以替換為canary包,RSC相關(guān)的功能就屬于canary包。
同理,通過npm update react@xperimental可以替換experimental包。
脫離Next.js使用RSC
在Next.js的App Router模式,所有組件默認(rèn)為服務(wù)端組件(即在服務(wù)端render的組件),只有當(dāng)組件所在文件頂部標(biāo)記了'use client'指令時,該組件是客戶端組件(即在前端render的組件)。
比如下面就是個客戶端組件:
'use client'
import {useState} from 'react';
function Cpn() {
const [num, update] = useState(0);
// ...省略
}實(shí)際上,這并不是Next.js自己的定義,而是RSC中的規(guī)范。在React文檔中,我們可以看到'use client'與'use server'規(guī)范的定義,其中:
- 'use client'用于標(biāo)記客戶端組件(在服務(wù)端,默認(rèn)所有組件都是服務(wù)端組件,所以客戶端組件需要專門標(biāo)記)。
- 'use server'用于標(biāo)記前端的某個函數(shù)為Server Action(可以在前端執(zhí)行的服務(wù)端邏輯)。
既然是規(guī)范,那就需要落地。在Next.js中,規(guī)范的落地都被收斂到Next.js框架內(nèi)部實(shí)現(xiàn)了。如果要脫離Next.js使用RSC,就需要我們自己落地規(guī)范。
RSC規(guī)范的落地包括三部分:
- 服務(wù)端編譯時
- 服務(wù)端運(yùn)行時
- 客戶端運(yùn)行時
這三者都被收斂到react-server-dom-webpack[2]包中。
接下來我們簡單講下這三部分的作用。
服務(wù)端編譯時
通過react-server-dom-webpack/plugin名字中的webpack、plugin字樣能看出,這是個webpack插件,配置類似如下:
const ReactServerWebpackPlugin = require("react-server-dom-webpack/plugin");
const config = {
// ...省略其他配置
plugins: [
new ReactServerWebpackPlugin({ isServer: false }),
],
}他的作用是識別項目中的'use client'指令,作用有些類似于「全自動React.lazy」。
使用過React.lazy特性的同學(xué)會知道,當(dāng)我們通過React.lazy懶加載組件時,懶加載的組件會被打包工具(比如webpack)打包成獨(dú)立的chunk。當(dāng)前端需要該組件時,會通過Jsonp請求chunk文件。
比如下面代碼中的./Cpn.jsx組件由于懶加載,會被打包成獨(dú)立的chunk:
import React from 'react';
const LayCpn = React.lazy(() => import('./Cpn.jsx'));
function App(props) {
return ;
}與React.lazy類似,當(dāng)我們在組件所在文件的頂部標(biāo)記'use client'時,并在服務(wù)端組件的子孫組件中使用到該組件,該組件代碼也會打包成獨(dú)立的chunk。由于這個過程是全自動的,所以可以稱為「全自動React.lazy」。
服務(wù)端運(yùn)行時
上面講到的編譯產(chǎn)物都是「客戶端組件對應(yīng)chunk」,所以他們是不會在服務(wù)端運(yùn)行時使用的。
服務(wù)端運(yùn)行時的作用類似SSR,都是給定JSX輸入,經(jīng)過render后獲得輸出。比如,給定如下輸入:
function App() {
return hello;
}對于SSR,會獲得字符串'
對于RSC規(guī)范,將輸入傳給react-server-dom-webpack/server導(dǎo)出的renderToPipeableStream方法,會獲得如下序列化數(shù)據(jù):
0:"$L1"
1:["$","div",null,{"children":"hello"}]再讓我們看一個稍微復(fù)雜點(diǎn)的例子:
我們有個組件Cpn,由于他包含客戶端狀態(tài)(使用了useState),所以只能作為客戶端組件(頂部標(biāo)記'use client'):
'use client'
import {useState} from 'react';
function Cpn() {
const [num, update] = useState(0);
// ...省略
}現(xiàn)在,我們的服務(wù)端組件App返回值中包含了Cpn:
function App() {
return ;
}經(jīng)由renderToPipeableStream方法,會獲得如下序列化數(shù)據(jù):
0:"$L1"
2:I["./src/app/Test.jsx",["client0","client0.chunk.js"],"Test"]
1:["$","div",null,{"children":["$","$L2",null,{}]}]可以發(fā)現(xiàn),序列化數(shù)據(jù)中并不包含具體的客戶端組件代碼,而是組件代碼對應(yīng)的文件(client0.chunk.js),這個文件就是我們在「服務(wù)端編譯時」打包產(chǎn)生的chunk文件。
客戶端運(yùn)行時
當(dāng)「服務(wù)端運(yùn)行時」產(chǎn)生的「序列化數(shù)據(jù)」傳遞給前端時,react-server-dom-webpack又出場了,這次使用的是react-server-dom-webpack/client。
這個包提供了幾個方法,用于將「從不同數(shù)據(jù)源獲取的序列化數(shù)據(jù)」轉(zhuǎn)換為「合法的React Element」,比如:
- createFromFetch:通過fetch方法獲取序列化數(shù)據(jù)。
- createFromReadableStream:通過可讀流獲取序列化數(shù)據(jù)。
對于上述序列化數(shù)據(jù):
0:"$L1"
2:I["./src/app/Test.jsx",["client0","client0.chunk.js"],"Test"]
1:["$","div",null,{"children":["$","$L2",null,{}]}]經(jīng)由react-server-dom-webpack/client中方法的轉(zhuǎn)換,會得到一個React.lazy組件,這樣前端的React就能正常render這個組件了。
總結(jié)
RSC規(guī)范屬于React特性,來自于React Canary。規(guī)范的落地可以通過react-server-dom-webpack包實(shí)現(xiàn)。
整個工作流程包括三個階段:
- 服務(wù)端編譯時,對應(yīng)react-server-dom-webpack/plugin。
- 服務(wù)端運(yùn)行時,對應(yīng)react-server-dom-webpack/server。
- 客戶端運(yùn)行時,對應(yīng)react-server-dom-webpack/client。
在Next.js中,RSC規(guī)范的落地被集成到框架內(nèi)部,做到了開箱即用的RSC,并在此基礎(chǔ)上衍生出更完善的功能(App Router)。
參考資料
[1]data-fetching-with-react-server-components:https://legacy.reactjs.org/blog/2020/12/21/data-fetching-with-react-server-components.html。
[2]react-server-dom-webpack:https://www.npmjs.com/package/react-server-dom-webpack。
分享題目:怎么理解ReactServerComponent和Next.js的關(guān)系
本文URL:http://m.fisionsoft.com.cn/article/cdppshi.html


咨詢
建站咨詢
