SolidJS硬氣的說(shuō):我比React還react
大家好,我是卡頌。
最近刷推時(shí),有個(gè)老哥經(jīng)常出現(xiàn)在前端框架相關(guān)推文下。

我想:“老哥你哪位?”
一查,原來(lái)是個(gè)框架作者,作品叫SolidJS。

翻翻框架介紹,這句話成功吸引我的注意:
支持現(xiàn)代前端特性,例如:JSX, Fragments, Context, Portals, Suspense, Streaming SSR, Progressive Hydration, Error Boundaries和Concurrent Rendering
我琢磨您不會(huì)是React在逃公主吧?這不能說(shuō)和React類似,只能說(shuō)完全一樣吧?

作為傳統(tǒng)中國(guó)人,秉承來(lái)都來(lái)了思想,我試用了一天,又看了下源碼,結(jié)果發(fā)現(xiàn)這個(gè)框架真是個(gè)寶藏框架。

本文會(huì)比較SolidJS與React的異同,闡述他的獨(dú)特優(yōu)勢(shì),看完后不知道你會(huì)不會(huì)和我發(fā)出同樣的感嘆:
這簡(jiǎn)直比React還react(react譯為響應(yīng))
相信看完本文后,不僅能認(rèn)識(shí)一個(gè)新框架,還能對(duì)React有更深的認(rèn)識(shí)。
開(kāi)整!
初看很相似
讓我們從一個(gè)計(jì)數(shù)器的例子看看與React語(yǔ)法的差異:
import { render } from "solid-js/web";
import { createSignal } from "solid-js";
function Counter() {
const [count, setCount] = createSignal(0);
const increment = () => setCount(count() + 1);
return (
<button type="button" onClick={increment}>
{count()}
</button>
);
}
render(() => <Counter />, document.getElementById("app"));
和React不同的地方:
useState改名成createSignal獲取
count狀態(tài)從React中直接使用count變?yōu)橥ㄟ^(guò)方法調(diào)用,即:count()
React框架?編譯時(shí)大不同
React的編譯時(shí)很薄,基本只是編譯JSX語(yǔ)法。SolidJS則采用了類似Svelte的方案:在編譯時(shí),將狀態(tài)更新編譯為獨(dú)立的DOM操作方法。一定條件下的體積優(yōu)勢(shì)
你不需要為你沒(méi)使用的代碼付出代價(jià)
React時(shí),即使沒(méi)有用到Hooks,其代碼也會(huì)出現(xiàn)在最終編譯后的代碼中。SolidJS中,未使用的功能不會(huì)出現(xiàn)在編譯后的代碼中。delegateEvents(["click"]);
document上注冊(cè)click事件代理。onClick,那么編譯后代碼中就不會(huì)有這一行。Svelte與React之間源代碼與編譯后代碼的體積差異。Svelte,藍(lán)色代表React:
SolidJS使用JSX描述視圖,比Svelte使用類似Vue的模版語(yǔ)法更靈活,所以在編譯時(shí)沒(méi)法做到Svelte一樣的極致編譯優(yōu)化,使得其相比Svelte運(yùn)行時(shí)更重一點(diǎn)。SolidJS的代碼體積比Svelte小25%左右。
更快的更新速度
React與Vue中存在一層虛擬DOM(React中叫Fiber樹(shù))。Diff算法),比較的結(jié)果會(huì)執(zhí)行不同的DOM操作(增、刪、改)。SolidJS與Svelte在發(fā)生更新時(shí),可以直接調(diào)用編譯好的DOM操作方法,省去了虛擬DOM比較這一步所消耗的時(shí)間。
React中,調(diào)用棧如下:
處理事件 對(duì)比并生成 Fiber樹(shù)根據(jù)對(duì)比結(jié)果執(zhí)行 DOM操作
SolidJS的更新路徑比React短很多。
響應(yīng)原理
name,初始值為KaSong。我們希望根據(jù)name渲染一個(gè)div。SolidJS編譯后的代碼類似:const [name, setName] = createSignal("KaSong");
const el = document.createElement("div");
createEffect(() => el.textContent = name());
createEffect類似React的useEffect。name,所以當(dāng)name改變后會(huì)觸發(fā)createEffect回調(diào),改變el.textContent,造成DOM更新。React的:useEffect(() => {
el.textContent = name;
}, [name])
<div>KaSong</div>setName("XiaoMing")
<div>XiaoMing</div>
name后會(huì)觸發(fā)createEffect?createEffect回調(diào)依賴name,所以會(huì)訂閱name的變化。由于篇幅有限,實(shí)現(xiàn)細(xì)節(jié)咱下回細(xì)聊。

SolidJS的狀態(tài)具有原子性。createEffect中如果使用了這些依賴,就會(huì)訂閱他們的變化。createEffect回調(diào)會(huì)執(zhí)行,進(jìn)而執(zhí)行具體的DOM方法,更新視圖。
React不是這樣么?Hooks會(huì)有調(diào)用順序不能變的要求?useEffect回調(diào)會(huì)有閉包問(wèn)題?React只有在這些限制下才能實(shí)現(xiàn)響應(yīng)式。辛勞苦干React
React并不關(guān)心哪個(gè)組件觸發(fā)了更新。React中,任何一個(gè)組件觸發(fā)更新(如調(diào)用this.setState),所有組件都會(huì)重新走一遍流程。因?yàn)樾枰獦?gòu)建一棵新的Fiber樹(shù)。render,React內(nèi)部有些優(yōu)化策略用來(lái)判斷組件是否可以復(fù)用上次更新的Fiber節(jié)點(diǎn)(從而跳過(guò)render)。API(比如:useMemo、PureComponent...),讓開(kāi)發(fā)者告訴他哪些組件可以跳過(guò)render。SolidJS的更新流程像一個(gè)畫(huà)家,畫(huà)面中哪兒需要更新就往哪兒畫(huà)幾筆。
React的更新流程像是一個(gè)人拿相機(jī)拍一張照片,再拿這張照片和上次拍的照片找不同,最后把不同的地方更新了。
總結(jié)
SolidJS與React的差異,主要體現(xiàn)在三方面:編譯時(shí) 運(yùn)行時(shí) 響應(yīng)原理
Hooks順序限制、沒(méi)有useEffect閉包問(wèn)題、沒(méi)有Fiber樹(shù)、比React更react的框架么?

評(píng)論
圖片
表情
