[筆記] Why React?

Mike Huang
麥克的半路出家筆記
10 min readMar 21, 2021

--

本篇是筆者透過 Complete React Developer in 2021 (w/ Redux, Hooks, GraphQL) 課程自學 React 的筆記及心得分享。相關練習的專案,將存放於 GitHub 中。

前言

今天要來筆記一下為什麼會使用 React 以及它的特性。在開始介紹前,需要先往前一步去了解當今主流的前端框架或函式庫出現前,是如何從 jQuery 的大量使用演進過來的。

jQuery 是 JavaScript 的函式庫,它的出現讓開發者得以用一套的語法,跨瀏覽器地取得和操作 DOM(Document Object Model)等功能,使得開發網頁更加輕鬆。

然而,隨著前端背負更多的邏輯、畫面渲染等工作,同時網頁規模變得更大更複雜時,事件的管理、資料的變化和關係等都變得更難掌握,導致維護和 Debug 上越來越困難。

此外,過去在開發上,開發者時常需要花很多的時間在處理 DOM 的取得和操作。同時間,當資料面變化後,也需要花很多的心力在將資料透過程式面,更新到頁面上,這麼做容易造成不必要的頁面更新,使得網頁效能降低。

React 的設計解決了許多這方面的問題,我們將下個段落更詳細的介紹它的特色有哪些。

React 核心特色

🚀 Don’t touch the DOM. I’ll do it.

以往通常是直接使用瀏覽器提供的 DOM API 操作 DOM,即便是使用 jQuery 等函式庫皆是,這種方式稱為 Imperative programming——根據各種事件驅動,直接操作和改變網頁中不同的區塊。然而其缺點就是當網頁功能及架構變大及複雜時,會越來越難掌握事件及其衍伸的狀態變化等。

以下圖中的網頁為例(由於在課程中的這個環節有在介紹 Angular 應此可以忽略左下角的 Logo),當區塊間帶有多組關聯,使用者的一個行為很可能造成多個區塊的變化,開發者就不容易在過程中去追蹤,甚至較難預測會發生哪些事情:

截圖自 Complete React Developer in 2021 (w/ Redux, Hooks, GraphQL) 課程

此外,DOM 的操作和改變容易造成網頁效能上的問題,其中值得關注的是瀏覽器需要做兩項非常有負擔的操作:

  • Reflow: 由 Render Tree 根結點出發,逐步計算出元素的大小和位置。
  • Repaint: 經過 Reflow 的計算,把結果轉換成螢幕上的實際像素顯示。

因此,React 採用的是 Declarative programming ——簡單來說,就是告訴它你希望最終的目標為何,由它來決定該使用什麼最有效率的方式來操作 DOM。

舉例來說:我們告訴 React 以下這就是我們的 App 的狀態和資料應該要長的樣子。接著就是告訴 React 頁面應該長怎麼樣子,根據狀態的變化,React 會自動找到最有效率的方式操作 DOM,做出變化,最終在頁面上呈現給使用者。因此,當使用者 isLoggedIn 的狀態變化時(例如:false → true),React 早就知道該做什麼來進行畫面更新。如此一來,作為開發者的我們,也不需要再花太多心力在 DOM 的操作,並將資料更新到畫面上,甚至可能還不小心因此參雜過多不必要的操作,造成效能降低,輕鬆許多。

App 的資料要長的樣子

這也是 React 名稱的由來:Based on the data or state of the app, which describes the app, React is going to react to it and change everything for you.

🚀 Build websites like lego blocks

React 讓我們能輕鬆打造「能被重複利用的元件」。透過組裝一個個小元件,我們能打造一個較大的元件,最終成為一個我們看到的完整專案。這些組件都能在專案中的不同地方重複被利用,甚至可以拿到不同的專案中被使用。

舉下圖為例,我們定義了一組 App 需要的資料,根據這組資料,能創建出一個元件,這個元件最終實際上代表的是左下角的綠色背景小元件。而這個小元件可能在專案多處都會出現,因此這個元件就能在多處被重複使用。而不用同樣的程式碼,在專案中的多處重複撰寫,使得管理上不方便。

截圖自 Complete React Developer in 2021 (w/ Redux, Hooks, GraphQL) 課程

🚀 Unidirectional data flow (One way data flow)

延續前面創建元件的方式——根據資料或狀態創建元件——緊接著會將狀態和剛創好的元件提供給 React(下圖中最底下函式),React 會創建所謂的 *VirtualDOM,用來幫助 React 判定該如何更新真實的 DOM。

截圖自 Complete React Developer in 2021 (w/ Redux, Hooks, GraphQL) 課程

因此,當我們希望頁面有所變更時,使用的狀態資料就必須有所變更——這就是所謂的 Unidirectional data flow——資料的流動是單一方向的。

舉例來說,當使用者點擊了一個按鈕,React 會攔截並詢問該做什麼。我們可以設計在這個狀況下,改變我們當前的狀態(或許是把上面例子中的 isLoggedIn 狀態改為 false)。而一旦狀態被改變了,React 會根據新的狀態,結合元件,決定該如何有效率的更新 DOM。

另一方面來說,當元件中的狀態變更了,便會將這個最新資訊往下傳遞給相關的子元件,告訴子元件狀態被變更了,並更新成在此最新狀態下的 App;由於資料是單向傳遞的,因此子元件的狀態無法往上傳遞。

截圖自 Complete React Developer in 2021 (w/ Redux, Hooks, GraphQL) 課程

當有了此限制——狀態被變更,由上往下傳遞至不同的元件——讓我們在管理上和遇到問題 Debug 時,會容易許多。我們只需要關注「資料存在何處,以及資料往哪個地方流去」。

想像上,它就是下面這樣子簡單的單向資料流:

透過資料狀態(State) 👉 創建元件渲染在頁面中(View) 👉 當使用者或 App 做了某些互動促使狀態被變更(Actions) 👉 透過資料狀態(State)👉 產生和呈現新的結果(View) 👉 …

截圖自 Complete React Developer in 2021 (w/ Redux, Hooks, GraphQL) 課程

❗️ViutualDOM 補充

The central idea of React’s API is to think of updates as if they cause the entire app to re-render.

前面有提到 React 是以數據面出發,當資料面有了變更(通常是透過 setState),如上面這句話所說的,React 希望直接進行頁面的重新渲染(re-rendering),而不探究到底是資料面的哪處被進行的改變。然而頁面的重新渲染成本其實是很高的,對於瀏覽器的負擔是很重的——因此有了 VirtualDOM 的實作和概念來解決這方面的問題。

首先,當渲染一個React App 時,React 會將 DOM 拷貝一份成為 JavaScript 物件,也就是所謂的 VirtualDOM。當資料面發生了變化,與其更新整個 DOM,應該更關注在受影響之處。因此,實際上 React 會將更新後的結果(不僅是更新後的資料,也包含受資料影響的元素結果)產生一份新的 VirtualDOM 出來。

最終,React 會拿新舊 VirtualDOM 進行比對,並只針對差異之處到實體的 DOM 中進行更新——這樣的優化過程就是所謂的 reconciliation。此外,多個 DOM 的更新,還可能透過批次的方式進行一次性的更新,大大的提升整體效能。

舉下圖為例,當資料面有所更新時,紅色的點代表那些受影響而改變的節點。經過前後的 VirtualDOM 比較後,最終將批次的更新到 DOM 當中。

圖片來源:https://www.oreilly.com/library/view/learning-react-native/9781491929049/ch02.html

的確,每次透過重新渲染而產生新的 VirtualDOM 也是有成本的,但比起直接(可能無效率地)操作 DOM,VirtualDOM 的產生和比較其實是相對快很多的,最終也只針對需要被變更之處到 DOM 中進行更新,因此效能可以被提升!

總的來說,當我們透過 React 在開發時,可以很輕鬆的只關注在資料狀態面的管理,最終 React 會在背後協助我們進行最有效率的 DOM 操作與更新。

🚀 UI, the rest is up to you

React 是用來實作 UI 的 JavaScript 函式庫——其著重在創建可重複使用的元件來實作 UI。假使開發者想要使用其他的功能,則可以載入不同的模組或函式庫來客製化應用程式。

這有點像是我們今天想煮湯,React 提供的就是一個爐子。至於你需要什麼其他的工具,如切版、勺子等,我們都可以想辦法向外取得用來煮湯。

由於 React 著重在建構 UI 這個基礎之上,React 就能被應用在不同技術和場景上。例如在打造網頁時,會使用 ReactDOM 這個工具,因為它了解該如何與網頁中的 DOM 做互動;雖然不認識手機的 UI,但藉由使用 ReactNative,就能以 React 為基礎應用在 Android 或 iOS 的 App 當中;甚至使用 React360 就能應用到 VR App 中。這也是常聽到的:Learn Once, Write Anywhere。

後記

雖然在這個階段的探索真的花了不少時間,甚至有點廢寢忘食 😅~但我覺得這卻是很重要的環節——畢竟框架或函式庫一個個推陳出新,實際上要學習如何使用應該都不會太難,但去了解其背後面對和要解決的問題,及其設計的方式和思考邏輯,其實才是最精華的地方,也能做為我們在未來評估使用與否的關鍵因素。

在了解基礎後,接下來將正式展開 React 的學習之旅了!期望自己有更多的所學,並有機會能記載下來,甚至做出更多更好的作品與產品!

最後,如果你喜歡這篇的分享,請不吝嗇的多點幾個 👏 給我超多鼓勵,感謝 :)

--

--

Mike Huang
麥克的半路出家筆記

熱愛接觸和學習網頁開發相關技術與知識、喜歡分享、旅遊和咖啡的軟體工程師 A software engineer who enjoy learning and sharing web technologies & fancy coffee and travelling