Writing

《React 101》先備知識

文章發表於

在真正進入到 React 前,我們不妨先理解一些基本概念,無論是學習或開發 React 多少都會看到這些概念的影子

HTML 結構

React 是一個 JavaScript 的套件用來建立使用者介面,而使用者介面 (網頁) 背後的基礎就是 HTML 與樹狀的資料結構 (Tree),舉以下的範例來說:

<ul>
<li>Apple</li>
<li>Banana</li>
<li>Peach</li>
</ul>

ulli 的父層項目 (parents),反之,對 ul 來說 li 就是子項目,而這種有母子關係的節點就是樹狀資料結構,我們可以對它進行任何操作,像是遍歷或是 CRUD。

ul
/ | \
/ | \
li li li
(Apple)(Banana)(Peach)

DOM

開發者(我們)使用 HTML 來建構網頁。當瀏覽器讀取 HTML 程式碼時,會在電腦記憶體中為每一個 HTML 元素建立對應的物件,並將這些元素組織成樹狀結構:包含根節點、父節點、子節點、孫節點等,以此類推形成層次關係。這個由物件組成的樹狀結構就是 DOM(Document Object Model),瀏覽器會基於此模型進行後續的渲染處理。

同時,DOM 是可以被操作的,當瀏覽器完成渲染時,我們仍然可以修改 DOM 樹的內容。當我們改變 DOM 時,瀏覽器會重新渲染(re-render),並更新使用者所看到的畫面。而這都是基於瀏覽器提供一系列的 API,像是 appendChild, removeChild 等等。

<!DOCTYPE html>
<html>

<head>
  <title>Parcel Sandbox</title>
  <meta charset="UTF-8" />
  <link rel="stylesheet" href="/styles.css" />
</head>

<body>
  <h1>Hello world</h1>
</body>

</html>

這也說明了,如果要建構動態的網頁,主要就是透過操作 DOM,這就帶來了一個新的議題,當網頁越來越複雜時,這些操作如果沒有有效優化,可能就會帶來一些效能上的麻煩,畢竟操作 DOM 是有成本的,瀏覽器必須更新 DOM 並且重新繪製 (repaint),同時開發者也必須找出更有效的方法管理這些程式碼。

宣告與命令函式

宣告與命令函式是兩種不同的程式設計風格,命令式 (Imperative) 需要去描述程式應該要如何完成某件事。而宣告式(Declarative)則是告訴程式你想要完成什麼。

舉例來說,當你想去某個地方時,命令式就像是給司機詳細路線指引:「直走 500 公尺,在 7-11 右轉,過兩個紅綠燈後左轉...」,而宣告式就像使用 Google Maps,你只需要輸入目的地,系統會自動規劃最佳路線。

但宣告式程式設計本質上是建立在命令式程式設計之上的一層抽象,這並不代表在底層沒有命令式程式碼。其實每一個宣告式系統底下都一定有命令式程式碼在執行那些明確的指令。

舉例來說,map 這個函式底層還是用 for loop 去實作,只是它提供一層抽象,讓我們開發者在使用 map 時不需要關心迴圈的細節、索引管理、或是陣列邊界檢查等問題,而能專注於「對每個元素要做什麼轉換」。

Array.prototype.myMap = function(callback, thisArg) {
const result = [];
for (let i = 0; i < this.length; i++) {
if (i in this) {
result[i] = callback.call(thisArg, this[i], i, this);
}
}
return result;
};
// [1, 2, 3, 4, 5].myMap(x => x * 2) // [2, 4, 6, 8, 10];

同樣地,當我們在 React 中寫 JSX 時,底層還是會轉換成一連串的 _jsx (更早以前是 createElement) 呼叫和 DOM 操作指令,而 React 就是幫我們處理底層命令式程式碼的工具,讓我們更容易去打造我們的網頁。

如果您喜歡這篇文章,請點擊下方按鈕分享給更多人,這將是對筆者創作的最大支持和鼓勵。
Buy me a coffee