十年回首:

React 的過去、現在與未來發展

 

 

 

Zet@WebConf 2024

2024.12.27

  • iCHEF 主任前端工程師

  • 近 11 年前端開發經驗,10 年 React 開發經經驗

  • 曾任 SITCON、JSDC 主議程講者

  • JSDC 2019 / 2020 議程組工作人員

  • 第 14 屆 IThome 鐵人賽 Modern Web 組冠軍

  • 《React 思維進化:一次打破常見的觀念誤解,躍升專業前端開發者》作者

Zet

周昱安

About me

React 誕生的時空背景

React 誕生的時空背景

  • 2011~2012 時代左右開始,前端網頁不再只是單純的靜態頁面,而逐漸朝向動態、互動式的應用程式邁進
    • 日益複雜的狀態資料以及畫面更新管理
    • 效能需求問題
    • 程式碼重用、管理的需求
  • Facebook 當時也面臨旗下重點產品 Facebook、Instagram 網頁版的開發、管理需求
  • Facebook 對於當時市面上的前端 MVC 框架都不滿意,所以決定自己在內部開發一套解決方案

React 誕生的時空背景

  • 2013 年,Facebook 在 JSConf 2013 發表並開源了 React
  • React 的設計理念著重解決:
    • 重用性:Component-based 設計
    • 狀態管理:單向資料流
    • 畫面更新 & 效能問題:Virtual DOM + Reconciliation

Component-based 設計

React 的單向資料流與畫面渲染策略

單向資料流:資料驅動畫面

  • 畫面結果是原始資料透過模板與渲染邏輯所產生的延伸結果
  • 當資料發生更新時,畫面才會產生對應的更新,以資料去驅動畫面

限縮變因的價值

  • 在單向資料流的設計模式下,資料變動基本上只會來自於開發者手動的觸發資料更新,而畫面結果也只會由原始資料與模板邏輯這兩種變因所構成
  • 限縮變因能帶來的好處:
    • 提高可維護性

    • 提升程式碼的可讀性

    • 減少資料意外出錯的風險

    • 更好的效能優化

實現單向資料流的 DOM 渲染策略

策略一:當資料更新後,人工判斷並手動修改所有

應受到連動更新的 DOM element

  • 優點:

    • 只要開發者 DOM 操作的夠簡潔精準的話,可以盡可能的減少因多餘DOM 操作造成的效能浪費

  • 缺點:

    • 完全依賴人為周全的判斷以及精確的操作 DOM 來維持單向資料流,在複雜的前端應用程式中非常困難

策略二:當資料更新後,一律將整個畫面的 DOM element

全部清除,再以最新的原始資料來全部重繪

  • 優點:

    • 開發者只需要關注模板定義以及資料更新的處理,不需要手動去維護資料連動的畫面操作,要維持單向資料流非常直覺簡單

  • 缺點:

    • 隨著應用程式的龐大與複雜,一律重繪的方式會因為大量不必要的 DOM操作而遇到明顯的效能問題,影響使用者體驗

前端框架的處理策略

  • 無論選擇以上的哪一種渲染策略,都有著明顯且難以解決的缺點

  • 大多數前端框架或解決方案都能透過一些特殊的架構設計來幫助我們解決資料連動畫面更新的需求,在保留這些渲染策略的優點的同時解決其缺點

    • 例如 Vue 採用了 MVVM 的設計模式,藉由 Proxy 監聽來源資料的改變,來自動更新該資料綁定的畫面區塊

Virtaul DOM

DOM 與 Virtual DOM

  • DOM 是一種樹狀資料結構,用於表示瀏覽器中的畫面元素
    • 操作 DOM 會連動瀏覽器的渲染引擎重繪畫面因而效能成本昂貴
  • Virtual DOM 是一種程式設計概念,它透過創建一個虛擬的畫面結構來模擬實際的 DOM,這種虛擬結構會持續同步化到與實際的 DOM,為 UI 管理提供了便利和效能優勢
  • Virtual DOM 並非從實際 DOM 複製而來。Virtual DOM 就像是開發者描繪的畫面試做品,用於先定義期望的畫面結構,然後程式再依據 Virtual DOM 的結構來操作實 際的 DOM,使其與 Virtual DOM 的結構保持一致,所以同步化的方向為由 Virtual DOM ⇒ DOM 單向。

React element

  • React element 是 React 基於 Virtual DOM 概念所實現的虛擬畫面結構元素,因此它是一種普通的 JavaScript 物件資料,用於描述一個預期的實際 DOM element 結構,同時也是作為在 React 中畫面結構描述的最小單位。

  • React element 可以透過呼叫 createElement 方法被建立,並且在經過 React 的處理轉換之後,就能自動產生對應的實際 DOM element。

建立 React element

React 中的一律重繪渲染策略

React 中的一律重繪渲染策略

  • Virtual DOM 這種概念在效能優化上的效益,是當畫面需要更新時,可以透過產生新的 Virtual DOM 畫面結構,然後比較新舊 Virtual DOM 畫面結構上的差異,並根據差異之處來執行最小範圍的實際 DOM 操作,以減少效能成本的浪費

  • 「資料更新後,一律清空畫面再重繪畫面」的 DOM 渲染策略,雖然開發者只需關注模板定義及資料更新的處理,不需手動維護資料連動的 DOM 細節操作,而使得單向資料流的維持變得直覺簡單,但是一律重繪畫面的方式會因為大量且不必要的 DOM element 增刪而造成效能問題,則也是無法忽略的缺點

既然一律重繪實際的 DOM 會導致大量的效能浪費,

那麼就改為一律重繪虛擬的畫面結構資料,也就是 React element

初始畫面的渲染

更新畫面的渲染

更新畫面的渲染

更新畫面的渲染

React 透過 Virtual DOM 概念與一律重繪渲染策略的結合,實現了可預測性高、易於維護且可靠的單向資料流,並同時避免了不必要的大量 DOM 操作所帶來的效能問題

Runtime 決定 UI

Class Component

Create React App (2016)

React Fiber (2017)

前端對於效能的需求日益增加

  • 前端對於「多任務」處理能力的需求增加
  • 任務的兩大分類
    • CPU 密集處理
    • I/O(data fetch / 使用者互動)
  • 任務之間的依賴關係
  • 任務之間的優先級關係

在 React Fiber 之前...

  • Render phase
    • 由父 component 層層往內部的子 component 呼叫來產生 UI 樹狀結構,形成一個遞迴的 stack
    • 這個 stack 的產生過程是同步且不可中斷的,因此當 render 某一塊樹狀結構過深或過於複雜的畫面時,就有可能佔用瀏覽器的 main thread 過久,導致其他瀏覽器工作產生延遲,影響使用者體驗
  • Commit phase
    • 這部分會呼叫瀏覽器 API 來更新實際的 DOM,因此本來就必定是同步且不可中斷的

可中斷的 render phase

  • 為了解決 render phase 可能佔用 main thread 過久所導致的效能問題,React 15 帶來了全新的底層架構 React Fiber:
    • 以 Linked list 代替一般的樹狀結構的儲存畫面結構
    • 將 render phase 產生畫面的的過程拆解成碎片化、可中斷的流程,透過全新的 scheduler 進行調度

Time Slicing

Concurrent React (2018)

Concurrent React

  • Code-splitting component with lazy()
  • Suspense loading placeholder

React Hooks (2019)

Class Component 的瓶頸

  • 寫法冗長、維護成本高

  • 重用邏輯的困難

  • 與新功能的整合受限

  • 生命週期方法易造成程式邏輯分散

  • 往函式式思維(Functional Programming)發展

Function Component

Function Component 透過一個簡單的 JavaScript 函式回傳 UI,不需要繁複的 class、生命週期方法,也不用手動綁定 this。搭配 Hooks,能讓你在函式裡同時管理狀態與副作用,寫起來更直觀,程式碼結構更簡潔,也更利於重複使用與維護。

參考資料

  • https://medium.com/starbugs/react-%E9%96%8B%E7%99%BC%E8%80%85%E4%B8%80%E5%AE%9A%E8%A6%81%E7%9F%A5%E9%81%93%E7%9A%84%E5%BA%95%E5%B1%A4%E6%9E%B6%E6%A7%8B-react-fiber-c3ccd3b047a1
  • https://www.bilibili.com/video/BV1LY411Q7hC/?buvid=05b9ac22d037c3ed5ae944ed83464318&is_story_h5=false&mid=YWERMxGK52sbiuZmkd8sYg%3D%3D&plat_id=116&share_from=ugc&share_medium=iphone&share_plat=ios&share_session_id=8FFB355E-118C-41A3-8D9D-E05875143341&share_source=COPY&share_tag=s_i&timestamp=1675165274&unique_k=jlqBDPr&up_id=43271611&fbclid=IwAR0oXXo8tBHttJJNJMkxYptSgw7XhdQMBqwMJBPFxDQ31RjlwK9OUVI2ZbE&vd_source=6b3f908b2077bd514bbd826b811a116c
  • https://www.youtube.com/watch?v=ByBPyMBTzM0
Made with Slides.com