大家好,我卡頌。
React
當前的穩定版本是18.2,釋出時間是22年6月,在此之後就沒有新的穩定版本釋出。
直到今年2月15日,官方部落格才透露下一個穩定版本的計劃。沒錯,他就是React19
。
為什麼時隔1年多才公佈下個穩定版本的計劃?
為什麼下個版本直接跳到了19?
18我都還沒升呢,19就來了,是不是要學很多東西?
這篇文章會為你詳細解答這些疑問。
免費領取卡頌原創React教程(原價359)、加入人類高質量前端群
從React16聊起
近年來React
最為人津津樂道的版本應該是16.8
,這個版本引入了Hooks
,為React
(乃至整個前端框架領域)注入了新的活力。
再之後的v17
沒有新特性引入。既然沒有新特性引入,為什麼要釋出一個大版本(從16到17)呢?
這是因為從同步更新升級到併發更新的React
,中間存在breaking change
。
這麼大體量的框架,在升級時需要保證過程儘可能平順。這除了是一種專業、負責的體現,更重要的,版本割裂會造成大量使用者損失(參考當年ng1
升級到anuglar2
時)。
當升級到18後,React團隊
發現 —— 真正升級到18,並大量使用併發特性(比如useTransition
)的開發者並不多。
更常見的場景是 —— 知名開源庫整合併發特性,開發者再直接用這些庫。
所以,React團隊
轉變策略,將迭代重心從賦能開發者轉變為賦能開源庫。那麼,什麼樣的庫受眾最多呢?顯然是框架。
所以,React
的重心逐漸變為 —— 賦能上層框架,開發者透過使用上層框架間接使用React
。
為什麼我說React團隊
轉變了策略,而不是React團隊
一開始的計劃就是賦能上層框架呢?
如果一開始的計劃就是賦能上層框架,React團隊
就不會花大量精力在版本的漸進升級上 —— 反正開發者最終使用的會是上層框架(而不是React
),版本割裂上層框架會解決,根本不需要引導開發者升級React
。
策略改變造成的影響
策略轉變造成的影響是深遠且廣泛的,這也是為什麼18.2後一年多都沒有新的穩定版本出現。
最基本的影響是 —— 特性的迭代流程變了。
React
誕生的初衷是為了解決Meta
內部複雜的前端應用,所以React
之前的特性迭代流程是:
- 新特性開發完成
- 新特性在
React
內部產品試用,並最終達到穩定狀態 - 開源供廣大開發者使用
但隨著策略轉變為賦能上層框架,勢必需要與主流上層框架團隊(主要是Next.js
)密切合作。
如果按照原來的迭代流程,上層框架團隊屬於Meta
之外的第三方團隊,只能等新特性開源後才能使用,這種合作模式顯然太低效了。
於是,React
團隊提出了一個新的特性發布渠道 —— canary
,即:新特性開發完成後,可以先打一個canary版本的React
供外部試用,等特性穩定後再考慮將其加入穩定版本中。
可能有些存在於canary
中的特性永遠不會出現在穩定版本的React
中,但不妨礙一些開源庫鎖死canary
版本的React
,進而使用這些特性。
那麼,為什麼時隔1年多才公佈下個穩定版本的計劃?主要有4個原因。
原因1:新特性主要服務於Next,沒必要出現在穩定版本中
策略改變除了影響特性的迭代流程,還讓React團隊成員
陷入一個兩難的境地 —— 我該優先服務上層框架還是Meta
?
我們可以發現,在之前的迭代流程中,一切都圍繞Meta
自身需求展開。React團隊成員
作為Meta
員工,這個迭代流程再自然不過。
但是,新的迭代流程需要密切與Next
團隊合作,那麼問題來了 —— 作為Meta
員工,新特性應該優先考慮Next
的需求還是Meta
的需求?
為了完成賦能上層框架的任務,顯然應該更多考慮Next
的需求。我們能看到一些React團隊成員
最終跳槽到Vercel
,進入Next
團隊。
所以,在此期間產出的特性(比如server action
、useFormStatus
、useFormState
)更多是服務於Next
,而不是React
。
如果基於這些特性發布新的穩定版本,那不用Next
的開發者用不到這些特性,用Next
的開發者依賴的是canary React
,所以此時升級穩定版本是沒意義的。
原因2:新特性必須滿足各種場景,交付難度大
Next
是web框架
,圍繞他創造的新React
特性只用考慮web
這一場景。
但React
自身的定位是宿主環境無關的UI庫
,還有大量開發者在非web
的環境使用React
(比如React Native
),所以這些特性要出現在穩定版本的React
中,必須保證他能適配所有環境。
舉個例子,Server Actions
這一特性,用於簡化客戶端與伺服器資料傳送的流程,當前主要應用於Next
的App Router
模式中。
比如下面程式碼中的MyForm
元件,當表單提交後,serverAction
函式的邏輯會在服務端執行,這樣就能方便的進行IO
操作(比如運算元據庫):
// 服務端程式碼
async function serverAction(event) {
'use server'
// 在這裡處理服務端邏輯,比如資料庫操作讀寫等
}
function MyForm() {
return (
<form action={serverAction}>
<input name="query" />
<button type="submit">Search</button>
</form>
);
}
App Router
的場景主要是RSC
(React Server Component),除了RSC
外,SSR
場景下是不是也有表單?不使用服務端相關功能,單純使用React
進行客戶端渲染,是不是也有表單的場景?
所以,Server Actions
特性後來改名為Actions
,因為不止Server
場景,其他場景也要支援Actions
。
比如下面程式碼中,在客戶端渲染的場景使用Actions
特性:
// 前端程式碼
const search = async (event) => {
event.preventDefault();
const formData = new FormData(event.target);
const query = formData.get('query');
// 使用 fetch 或其他方式傳送資料
const response = await fetch('/search', /*省略*/);
// ...處理響應
};
function MyForm() {
return (
<form action={search}>
<input name="query" />
<button type="submit">Search</button>
</form>
);
}
你以為這就完了?還早。form
元件支援Actions
,那開發者自定義的元件能不能支援Actions
這種前、後端互動模式?
比如下面的Calendar
元件,之前透過onSelect
事件響應互動:
<Calendar onSelect={eventHandler}>
以後能不能用Actions
的模式響應互動:
<Calendar selectAction={action}>
如何將平平無奇的互動變成Actions互動
呢?React團隊
給出的答案是 —— 用useTransition
包裹。所以,這後面又涉及到useTransition
功能的修改。
Actions
只是一個例子,可以發現,雖然新特性是以web
為始,但為了出現在穩定版本中,需要以覆蓋全場景為終,自然提高了交付難度。
原因3:老特性需要相容的場景越來越多,工作量很大
新特性越來越多,老特性為了相容這些新特性也必須作出修改,這需要大量的時間開發、測試。
舉兩個例子,Suspense
在v16.6就引入了,它允許元件“等待”某些內容變得可用,並在此期間顯示一個載入指示器(或其他後備內容)。
Suspense
最初只支援懶載入元件(React.lazy
)這一場景。隨著React
新特性不斷湧現,Suspense
又相繼相容瞭如下場景:
Actions
提交後的等待場景- 併發更新的等待場景
Selective Hydration
的載入場景RSC
流式傳輸的等待場景- 任何
data fetching
場景
為了相容這些場景,Suspense
的程式碼量已經非常恐怖了,但開發者對此是無感知的。
再舉個和Suspense
、useEffect
這兩個特性相關的例子。
Suspense
為什麼能在中間狀態與完成狀態之間切換?是因為在Suspense
的原始碼中,他的內部存在一個Offscreen
元件,用於完成兩顆子Fiber樹
的切換。
React團隊
希望將Offscreen
元件抽離成一個單獨的新特性(新名字叫Activity
元件),起到類似Vue
中Keep-Alive
元件的作用。
Activity
元件既然能讓元件顯/隱,那勢必會影響元件的useEffect
的觸發時機。畢竟,如果一個元件隱藏了,但他的useEffect create
函式觸發了,會是一件很奇怪的事情。
所以,為了落地Activity
元件,useEffect
的觸發邏輯又會變得更復雜。
原因4:特性必須形成體系才能交付
雖然這一年React團隊
開發了很多特性,但很多特性無法單獨交付,必須構成一個體系後再統一交付。
比如剛才提到的useFormStatus
、useFormState
是服務於Actions
特性的,Actions
又是由Server Actions
演化而來的,Server Actions
又是RSC
(React服務端元件)體系下的特性。
單獨將useFormStatus
釋出在穩定版本中是沒意義的,他屬於RSC
體系下的一環。
所以,即使新特性已經準備就緒,他所在的體系還沒準備好的話,那體系下的所有特性都不能在穩定版本中交付。
總結
為什麼時隔1年多才公佈下個穩定版本的計劃?主要是4個原因:
- 新特性主要服務於Next,沒必要出現在穩定版本中
- 新特性必須滿足各種場景,交付難度大
- 老特性需要相容的場景越來越多,工作量很大
- 特性必須形成體系才能交付
那為什麼下個穩定版本不是v18.x而是v19呢?這是因為部分新特性(主要是Asset Loading
、Document Metadata
這兩類特性)對於一些應用會產生breaking change
,所以需要發一個大版本。
從上述4個原因中的第四點可以知道,既然有v19的訊息,勢必是因為已經有成體系的新特性可以交付,那是不是意味著要學很多東西呢?
這一點倒不用擔心,如果你不用Next
,那你大機率不會接觸到RSC
,既然不會接觸RSC
,那麼RSC
體系下的新特性你都不會用到。
v19對你最大的影響可能就是新特性對老API的影響了,比如:
useContext
變為use(promise)
Activity
元件使useEffect
的觸發時機更復雜(應該不會在v19的第一個版本中)
這些的學習成本都不大。
關於v19的進一步訊息,會在今年5月15~16的React Conf公佈。