1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        SolidJS硬氣的說(shuō):我比React還react

        共 3775字,需瀏覽 8分鐘

         ·

        2021-09-14 23:31

        作者:卡頌
        來(lái)源:SegmentFault 思否社區(qū)


        大家好,我是卡頌。

        最近刷推時(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ì)比較SolidJSReact的異同,闡述他的獨(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()

        難道僅僅是一個(gè)類React框架?
        別急,讓我們從編譯時(shí)、運(yùn)行時(shí)響應(yīng)原理三方面來(lái)看看。

        編譯時(shí)大不同

        React的編譯時(shí)很,基本只是編譯JSX語(yǔ)法。
        SolidJS則采用了類似Svelte的方案:在編譯時(shí),將狀態(tài)更新編譯為獨(dú)立的DOM操作方法。
        這樣做有什么好處?主要有兩點(diǎn)。

        一定條件下的體積優(yōu)勢(shì)

        你不需要為你沒(méi)使用的代碼付出代價(jià)
        使用React時(shí),即使沒(méi)有用到Hooks,其代碼也會(huì)出現(xiàn)在最終編譯后的代碼中。
        而在SolidJS中,未使用的功能不會(huì)出現(xiàn)在編譯后的代碼中。
        舉個(gè)例子,上面計(jì)時(shí)器的例子中,編譯后的代碼有一行是這樣:
        delegateEvents(["click"]);
        這行代碼的目的是在document上注冊(cè)click事件代理。
        如果在計(jì)時(shí)器中沒(méi)有使用onClick,那么編譯后代碼中就不會(huì)有這一行。
        有熱心網(wǎng)友對(duì)比了類似編譯時(shí)方案的SvelteReact之間源代碼編譯后代碼的體積差異。
        其中橫軸代表源代碼體積,縱軸代表編譯后代碼體積,紅色線條代表Svelte,藍(lán)色代表React
        可見(jiàn),在臨界值(業(yè)務(wù)源代碼體積達(dá)到120kb)之前,編譯時(shí)方案有一定體積優(yōu)勢(shì)。
        由于SolidJS使用JSX描述視圖,比Svelte使用類似Vue的模版語(yǔ)法更靈活,所以在編譯時(shí)沒(méi)法做到Svelte一樣的極致編譯優(yōu)化,使得其相比Svelte運(yùn)行時(shí)更重一點(diǎn)。
        這為他帶來(lái)了額外的好處:在真實(shí)項(xiàng)目(>120kb)中,SolidJS的代碼體積比Svelte小25%左右。
        還真是,因禍得福?


        更快的更新速度

        我們知道,在ReactVue中存在一層虛擬DOMReact中叫Fiber樹(shù))。
        每當(dāng)發(fā)生更新,虛擬DOM會(huì)進(jìn)行比較(Diff算法),比較的結(jié)果會(huì)執(zhí)行不同的DOM操作(增、刪、改)。
        SolidJSSvelte在發(fā)生更新時(shí),可以直接調(diào)用編譯好的DOM操作方法,省去了虛擬DOM比較這一步所消耗的時(shí)間。
        舉個(gè)例子,上文的計(jì)時(shí)器,當(dāng)點(diǎn)擊后,從觸發(fā)更新到視圖變化的調(diào)用棧如下:


        觸發(fā)事件,更新?tīng)顟B(tài),更新視圖,一路調(diào)用走到底,清晰明了。
        同樣的例子放到React中,調(diào)用棧如下:


        左中右紅、綠、藍(lán)框調(diào)用棧分別對(duì)應(yīng):
        • 處理事件
        • 對(duì)比并生成Fiber樹(shù)
        • 根據(jù)對(duì)比結(jié)果執(zhí)行DOM操作
        可見(jiàn),SolidJS的更新路徑比React短很多。


        你問(wèn)憑什么?這還得從其特殊的響應(yīng)原理聊起。

        響應(yīng)原理

        假設(shè)有個(gè)狀態(tài)name,初始值為KaSong。我們希望根據(jù)name渲染一個(gè)div。
        SolidJS編譯后的代碼類似:
        const [name, setName] = createSignal("KaSong");

        const el = document.createElement("div");
        createEffect(() => el.textContent = name());
        其中createEffect類似ReactuseEffect。
        由于其回調(diào)內(nèi)依賴了name,所以當(dāng)name改變后會(huì)觸發(fā)createEffect回調(diào),改變el.textContent,造成DOM更新。
        類似React的:
        useEffect(() => {
          el.textContent = name;
        }, [name])
        首屏渲染結(jié)果:
        <div>KaSong</div>
        接下來(lái),觸發(fā)更新:
        setName("XiaoMing"
        更新后結(jié)果:
        <div>XiaoMing</div>
        為什么更新name后會(huì)觸發(fā)createEffect
        這里也沒(méi)有什么黑魔法,就是訂閱發(fā)布。
        createEffect回調(diào)依賴name,所以會(huì)訂閱name的變化。
        由于篇幅有限,實(shí)現(xiàn)細(xì)節(jié)咱下回細(xì)聊。




        這里的關(guān)鍵在于,SolidJS的狀態(tài)具有原子性。
        即狀態(tài)互相之間有依賴關(guān)系,他們形成局部的依賴圖。當(dāng)改變一個(gè)狀態(tài)后,依賴圖中的其他狀態(tài)也會(huì)改變。
        createEffect中如果使用了這些依賴,就會(huì)訂閱他們的變化。
        當(dāng)狀態(tài)改變后,createEffect回調(diào)會(huì)執(zhí)行,進(jìn)而執(zhí)行具體的DOM方法,更新視圖。
        。響應(yīng)式更新,指哪打哪,李云龍直呼內(nèi)行。


        有同學(xué)會(huì)問(wèn),React不是這樣么?
        那我問(wèn)你個(gè)問(wèn)題:
        為什么Hooks會(huì)有調(diào)用順序不能變的要求?
        為什么useEffect回調(diào)會(huì)有閉包問(wèn)題?
        答案已經(jīng)呼之欲出了:React只有在這些限制下才能實(shí)現(xiàn)響應(yīng)式。

        辛勞苦干React

        有一個(gè)可能反直覺(jué)的知識(shí):React并不關(guān)心哪個(gè)組件觸發(fā)了更新。
        React中,任何一個(gè)組件觸發(fā)更新(如調(diào)用this.setState),所有組件都會(huì)重新走一遍流程。因?yàn)樾枰獦?gòu)建一棵新的Fiber樹(shù)。
        為了減少無(wú)意義的render,React內(nèi)部有些優(yōu)化策略用來(lái)判斷組件是否可以復(fù)用上次更新的Fiber節(jié)點(diǎn)(從而跳過(guò)render)。
        同時(shí),也提供了很多API(比如:useMemoPureComponent...),讓開(kāi)發(fā)者告訴他哪些組件可以跳過(guò)render
        如果說(shuō),SolidJS的更新流程像一個(gè)畫(huà)家,畫(huà)面中哪兒需要更新就往哪兒畫(huà)幾筆。


        那么React的更新流程像是一個(gè)人拿相機(jī)拍一張照片,再拿這張照片和上次拍的照片找不同,最后把不同的地方更新了。


        總結(jié)

        今天,我們聊了SolidJSReact的差異,主要體現(xiàn)在三方面:
        • 編譯時(shí)
        • 運(yùn)行時(shí)
        • 響應(yīng)原理
        不知道你喜歡這款:沒(méi)有Hooks順序限制、沒(méi)有useEffect閉包問(wèn)題、沒(méi)有Fiber樹(shù)、比Reactreact的框架么?
        如果你問(wèn)我選哪個(gè)?當(dāng)然,哪個(gè)給工資高我用哪個(gè)。


        點(diǎn)擊左下角閱讀原文,到 SegmentFault 思否社區(qū) 和文章作者展開(kāi)更多互動(dòng)和交流,掃描下方”二維碼“或在“公眾號(hào)后臺(tái)回復(fù)“ 入群 ”即可加入我們的技術(shù)交流群,收獲更多的技術(shù)文章~

        - END -


        瀏覽 67
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            中文字幕人妻一区二区三 | 少妇寂寞小伙满足少妇在线观看 | 国产夫妻性爱视频 | 20岁小美女被操棉毛小嫩逼精彩视频 | 国产久 | 日日操人人操 | 亚洲黄色电影大全 | 国产免费拔擦拔擦8x在线下载 | 国产精品露脸视频 | 午夜逼逼|