「讓我先問你一個問題:如果有人說用 HTML + CSS + JavaScript 就能做網頁,為什麼還需要 React?」
這篇帶你親手感受那個痛點。我們先用純 JavaScript 做一個待辦清單, 讓你真實體會「手動操作 DOM」有多麻煩——然後你就會懂 React 為什麼存在了。
先做一個原生 JS 待辦清單
先別碰 React。我們用最原始的 HTML + JavaScript 來做一個能「新增、勾選完成、刪除」的待辦清單。 這個版本完全可以運作——先看它怎麼寫的:
這個版本「可以用」。功能都有:新增、完成、刪除、計數器。 但等等——你有沒有注意到 render() 出現了三次? 而且每次改資料之後,你都要記得手動呼叫它。
這裡有什麼問題?
乍看之下沒什麼大問題。但等到你要加功能——「按重要度排序」、「只顯示未完成」、「每筆待辦有截止日」—— 問題就開始浮現。讓我們拆開來看:
每次都要手動更新 DOM
你改了資料(todos 陣列), 畫面不會自動更新——你必須記得呼叫 render()。 如果你忘了,畫面和資料就不同步了。功能越多,需要呼叫 render() 的地方越多,越容易漏掉。
render() 效率差
每次 render() 都先 list.innerHTML = '' 清空整個列表,再重建所有項目。 你點了一個「完成」按鈕,結果整個列表都重建了——包括那些根本沒變的待辦事項。 清單 100 筆,你改一筆,100 筆全部重新建 DOM。
程式碼越來越難維護
加一個「按重要度排序」功能,你需要在十幾個地方更新邏輯,還要記得呼叫 render()。 「只顯示未完成」功能也一樣。每加一個功能,複雜度就跳一個量級。 六個月後換人接手(或六個月後的自己接手),根本看不懂資料和畫面之間的關係。
Excel 比喻
就像你在 Excel 裡用公式 SUM,但每次改了數字, 你要手動按 F9 才會更新——這不對,公式就應該自動計算。 React 就是讓畫面能「自動計算」。你只需要說「這格的值是什麼」, 計算的事讓工具幫你做。
React 怎麼解決這個問題
把剛才的待辦清單改寫成 React 版本。對比著看,你就會懂核心差異在哪:
原生 JS 版本的負擔
- ✗ 每次改資料都要手動呼叫 render()
- ✗ render() 清空整個 DOM 再重建
- ✗ 資料和 DOM 操作混在一起
- ✗ 計數器要單獨記得更新
React 版本的差異
- ✓ setTodos() 之後畫面自動更新
- ✓ React 只更新有差異的部分
- ✓ 你只管資料,不管 DOM
- ✓ 計數器 {todos.length} 自動同步
React 的核心思想
你只需要說明資料是什麼(todos), 以及怎麼更新資料(setTodos)。 畫面的事,React 幫你搞定。
UI 是資料的函式。資料變了,UI 自動跟著變。
Virtual DOM——React 為什麼快
你可能會想:「React 畫面自動更新,那它不是每次都重建整個 DOM 嗎?那不是更慢?」 答案是——React 用了 Virtual DOM,讓更新變得聰明很多。
裝修房子的比喻
想像你要裝修一間房子。
傳統做法(原生 JS):每次有任何改動,就把整個房子拆掉重建。換個燈泡也拆整棟。
React 的做法:先在腦袋裡(Virtual DOM)規劃好改動,比對前後差異, 只搬那幾件家具、換那顆燈泡,其他不動。不拆整間房子。
原生 JS 更新流程
React 更新流程
Virtual DOM 是 React 在記憶體中維護的一份 DOM 樹的輕量描述。 每次狀態改變,React 先更新 Virtual DOM,再比較前後兩棵樹的差異(reconciliation), 最後只把真正有變化的部分同步到瀏覽器的實際 DOM。 這個過程叫做 Diffing。
React 的三個核心心法
React 不只是一個「讓 DOM 操作變簡單」的工具,它背後有一套設計哲學。 理解這三個心法,你學 React 的速度會快很多:
UI = f(state)
把注意力放在「資料」,不是「DOM 操作」。你只需要描述「當資料是 X 時,畫面長什麼樣子」。 React 的工作是把這個描述轉換成真實的 DOM 並保持同步。 你不再需要思考「我要操作哪個 DOM 元素」——只需要思考「資料應該長什麼樣子」。
單向資料流
資料從上往下傳(父組件 → 子組件),只能透過 Props 傳遞。 這讓你永遠知道「這個資料從哪來」——不會有資料從四面八方湧入、你搞不清楚誰改了什麼的狀況。 單向流讓 debug 變得容易:追蹤資料的源頭,就能找到問題所在。
組件化(Component)
把 UI 拆成獨立的積木,每個積木只管自己的邏輯。<TodoItem /> 只管一筆待辦事項的顯示,<TodoList /> 只管清單的排列,<TodoApp /> 管整個應用的狀態。 每個積木可以獨立開發、測試、重複使用。
本篇重點回顧
現在你知道為什麼需要 React 了。下一篇就直接進去:Component、JSX、Props、State——React 的四個核心積木。
上一篇
EP.14 — TypeScript 入門
型別系統 · Interface · Generics
下一篇
EP.04 — React 核心概念
Component · JSX · Props · State