Logo

新人日誌

首頁關於我部落格

新人日誌

Logo

網站會不定期發佈技術筆記、職場心得相關的內容,歡迎關注本站!

網站
首頁關於我部落格
部落格
分類系列文

© 新人日誌. All rights reserved. 2020-present.

React 的特色是什麼?初學者必懂的核心觀念

最後更新:2026年2月27日JavaScript

在上一篇文章中,我們了解了 React 的誕生背景。

這篇文章要更進一步,帶你認識 React 的核心特色,以及它跟 jQuery 在思維上的根本差異。

React 只做 View:它跟 MVC 框架有什麼不同?

要理解 React 的特色,最好的方式是先說明它不做什麼。

在軟體開發中,有一個常見的程式碼組織方式叫做 MVC。

MVC 是 Model(資料)、Controller(控制)、View(畫面)的縮寫,核心概念是把程式碼分成三個職責:「資料怎麼管理」、「邏輯怎麼處理」、「畫面怎麼顯示」。

為什麼要這樣分?因為如果所有程式碼都混在一起,當專案變大的時候,你會分不清楚哪段程式碼在處理資料、哪段在控制流程、哪段在更新畫面。

把職責分開,每個部分各司其職,程式碼才不會亂成一團。

2013 年 React 剛發表的時候,最主流的前端框架 AngularJS(Angular 1)就是採用 MVC 的方式來組織程式碼。

AngularJS 幫開發者把很多事情都規劃好了:畫面怎麼顯示、頁面之間怎麼跳轉、表單怎麼驗證、前端的資料怎麼管理——你只要照著它的規範寫,這些功能就都有了。

而 React 官方當時寫了一句很有名的話: 「React is just the V in MVC」 (React 只是 MVC 中的 V)。

這句話的意思是:AngularJS 幫你把三件事都做完,而 React 只負責其中一件——把資料變成使用者看到的畫面。

至於頁面跳轉、表單驗證、資料管理這些功能,React 通通不管,你需要自己選擇其他工具來搭配。

後來社群也確實發展出了各種搭配工具,例如處理頁面跳轉的 React Router、處理資料管理的 Redux 等等。

這聽起來好像很麻煩,但反過來想,正因為 React 只做一件事,你可以根據專案的需求自由選擇最適合的工具,而不是被框架綁死只能用它提供的方案。

React 不用模板語法,只用 JavaScript

上面提到,React 只負責 MVC 中的 V(View),也就是畫面的部分。

但這裡有一個問題:在 MVC 的世界裡,View 通常是用 模板(Template) 來產生的。

什麼是模板?要理解模板,你需要先知道它涉及三個角色:

資料(Data) ——存放在程式裡的原始資料,例如 userName = "小明"、followerCount = 500。這些資料不會直接顯示在畫面上,它們只是存在程式記憶體裡的一些值。

模板(Template) ——一份預先寫好的 HTML 結構,裡面留了一些空位,標記著「這裡要放某筆資料」。

模板引擎(Template Engine) ——負責把資料填進模板空位的工具,填完之後就會產生出使用者最終看到的畫面。

用一個個人頁面的例子來看這三者怎麼配合:

首先,程式裡有一份資料:

userName = "小明"
followerCount = 500

然後,有一份模板,裡面用 {{ }} 標記了空位:

<h1>{{ userName }}</h1>
<p>粉絲數:{{ followerCount }}</p>

最後,模板引擎會把資料填進對應的空位,產生出最終的畫面:

<h1>小明</h1>
<p>粉絲數:500</p>

這種「資料和畫面分開管理,再由模板引擎組合起來」的做法非常普遍,不管前端還是後端,到處都在用:

領域框架 / 模板引擎模板語法範例
後端(Node.js)EJS, Pug<%= name %>
後端(Python)Jinja2, Django Template{{ name }}
後端(Java)Thymeleafth:text="${name}"
前端Handlebars, Mustache{{name}}
前端Angular*ngFor, {{ item.name }}
前端Vuev-for, {{ item.name }}
框架 / 模板引擎EJS, Pug
模板語法範例<%= name %>
框架 / 模板引擎Jinja2, Django Template
模板語法範例{{ name }}
框架 / 模板引擎Thymeleaf
模板語法範例th:text="${name}"
框架 / 模板引擎Handlebars, Mustache
模板語法範例{{name}}
框架 / 模板引擎Angular
模板語法範例*ngFor, {{ item.name }}
框架 / 模板引擎Vue
模板語法範例v-for, {{ item.name }}

你會發現,每個框架都有自己的一套模板語法。

雖然它們做的事情都差不多(把資料塞進畫面),但寫法各不相同,換一個框架就要重新學一套。

以前端為例,假設你想在畫面上顯示一個待辦清單。

用 Angular 的寫法會長這樣:

<!-- Angular 的模板語法 -->
<ul>
  <li *ngFor="let item of items">{{ item.name }}</li>
</ul>

用 Vue 的寫法會長這樣:

<!-- Vue 的模板語法 -->
<ul>
  <li v-for="item in items">{{ item.name }}</li>
</ul>

裡面的 *ngFor 和 v-for 都是框架自己發明的語法,你必須額外去學才知道它們是什麼意思。

而 React 在這件事上做了一個不同的選擇:它不用模板。

React 直接用 JavaScript 來建構畫面。

這代表你不需要去記 *ngFor、v-for、{{ }} 這些框架專屬的語法。

想要跑迴圈?用 JavaScript 的迴圈。想要加判斷?用 JavaScript 的 if。想要處理陣列?用 JavaScript 的 .map()。

也就是說,只要你會 JavaScript,就已經具備寫 React 的基礎了,不用為了 React 額外學一套新的語言。

這也讓 React 的學習曲線更平滑——你花時間學的是 JavaScript 本身,而這個技能不管未來用不用 React,都不會浪費。

React 單向資料流:資料變了,畫面自動更新

上一段提到,模板的做法是把資料填進畫面。

但模板只解決了一半的問題。

回想一下上一段的例子:程式裡的資料是 followerCount = 500,模板引擎把它填進模板的空位,畫面就顯示出「粉絲數:500」。

可是如果有人追蹤了小明,程式裡的資料從 followerCount = 500 變成 followerCount = 501 了呢?

畫面上的數字要怎麼跟著從 500 變成 501?

這就是下一個要解決的問題: 當程式裡的資料改變了,畫面要怎麼跟著更新?

像 Angular 的做法是 雙向綁定 。

用一個具體的例子來說明:假設畫面上有一個輸入框,讓使用者填寫暱稱,而程式裡有一筆對應的資料 userName = ""。

在雙向綁定中,使用者在輸入框裡打了「小明」,程式裡的資料會自動變成 userName = "小明"——這個方向很好理解。

// 方向一:畫面 → 資料
// 使用者在輸入框打字

輸入框顯示:小明
         ↓ (自動同步)
程式裡的資料:userName = "小明"

但反過來也成立:假設旁邊有一個「隨機產生暱稱」的按鈕,按下去之後程式把資料改成 userName = "快樂熊貓",這時候輸入框裡顯示的文字也會自動從「小明」變成「快樂熊貓」。

// 方向二:資料 → 畫面
// 使用者按下「隨機產生暱稱」按鈕

程式裡的資料:userName = "快樂熊貓"
         ↓ (自動同步)
輸入框顯示:快樂熊貓

也就是說,資料和畫面之間是互相影響的,不管從哪一邊改,另一邊都會自動同步。

當專案小、畫面單純的時候,這樣做很方便。

但當專案變大,畫面上有很多組件都跟同一份資料綁定的時候,問題就來了:

flowchart LR
    A["暱稱輸入框<br>使用者打字"] <-->|"自動同步"| D["資料(Data)<br>userName = ???"]
    B["隨機暱稱按鈕<br>程式改資料"] <-->|"自動同步"| D
    C["個人頁面<br>顯示暱稱"] <-->|"自動同步"| D
    E["通知欄<br>顯示暱稱"] <-->|"自動同步"| D

    style A fill:#50B86C,stroke:#3A8A4F,color:#fff
    style B fill:#50B86C,stroke:#3A8A4F,color:#fff
    style C fill:#50B86C,stroke:#3A8A4F,color:#fff
    style E fill:#50B86C,stroke:#3A8A4F,color:#fff
    style D fill:#E74C3C,stroke:#C0392B,color:#fff

輸入框可以改 userName、隨機暱稱按鈕也可以改、個人頁面和通知欄也都綁著同一份資料。

當 userName 的值突然不對的時候,你要從這四個地方一個一個去查,到底是誰、在什麼時候改了它。

畫面越多,追蹤的難度就越高。

React 的做法不同,它採用 單向資料流 :資料只能往一個方向流動。

同樣是暱稱的例子,在 React 裡會變成這樣:

flowchart LR
    A["資料(Data)<br>userName = '小明'"] -->|"1.資料驅動畫面"| B["暱稱輸入框<br>顯示:小明"]
    A -->|"1.資料驅動畫面"| D["個人頁面<br>顯示:小明"]
    A -->|"1.資料驅動畫面"| E["通知欄<br>顯示:小明"]
    B -->|"2.使用者打字"| C["事件處理<br>onChange"]
    C -->|"3.主動更新資料"| A

    style A fill:#4A90D9,stroke:#2E6BA6,color:#fff
    style B fill:#50B86C,stroke:#3A8A4F,color:#fff
    style C fill:#F5A623,stroke:#C4841C,color:#fff
    style D fill:#50B86C,stroke:#3A8A4F,color:#fff
    style E fill:#50B86C,stroke:#3A8A4F,color:#fff

在 React 裡,暱稱輸入框、個人頁面、通知欄都只是「接收資料並顯示」,它們不能反過來直接修改資料。

如果使用者在輸入框打字,React 不會自動把輸入的內容同步到資料裡。

那畫面要怎麼更新?你需要透過 事件處理 來主動更新資料。

什麼是事件處理?「事件」就是使用者在畫面上做的任何操作——打字、點擊按鈕、滑動頁面,這些都是事件。而「事件處理」就是你預先寫好的一段程式,告訴 React:「當這個事件發生的時候,要做什麼事。」

用暱稱輸入框的例子來看,整個流程是這樣的:

// 第一步:使用者在輸入框打了「小明」
// 這個動作觸發了 onChange 事件

// 第二步:事件處理程式收到通知,主動更新資料
事件處理:把 userName 從 "" 更新成 "小明"

// 第三步:React 偵測到資料變了,自動重新產生畫面
資料:userName = "小明"
         ↓(React 自動更新)
暱稱輸入框顯示:小明
個人頁面顯示:小明
通知欄顯示:小明

注意第二步——資料不是「自動」變的,而是你在事件處理裡 明確寫了一行程式 去更新它。

這多了一個步驟,但好處是:每一次 userName 的改變,都一定是從某個事件處理觸發的。

當 userName 的值不對的時候,你只需要去找「哪個事件處理改了 userName」就好,不用像雙向綁定那樣,從四個地方一個一個去猜是誰改的。

另外,你可能會有一個疑問:如果每次資料一變,React 就重新產生畫面,那不會很慢嗎?

假設頁面上有 1000 個元素,但其實只有暱稱那一個地方需要更新,如果 React 把整個頁面砍掉重建,那效能一定很差。

React 的解決方式是 Virtual DOM(虛擬 DOM) 。

DOM 是什麼?簡單來說,DOM 就是瀏覽器用來呈現網頁的結構。你在畫面上看到的每一個按鈕、文字、圖片,在瀏覽器背後都對應著一個 DOM 元素。直接操作 DOM 是很花效能的,因為每改一個元素,瀏覽器就可能需要重新計算排版和重新繪製畫面。

React 的做法是:它不直接去動瀏覽器的 DOM。

當資料改變的時候,React 會先在記憶體裡產生一份新的畫面描述(這就是 Virtual DOM),它就像是一份「畫面的草稿」。

然後 React 會拿這份新的草稿,跟上一次的草稿做比對,找出「到底哪裡不一樣」。

最後,React 只把真正有變化的部分更新到瀏覽器的 DOM 上。

延續上面的例子:使用者把暱稱從「小明」改成「快樂熊貓」,React 比對之後發現只有暱稱相關的元素變了,就只更新那幾個地方,頁面上其他 990 多個元素完全不會被動到。

這代表不管你的頁面有多複雜,React 每次都只做最少、最必要的更新,效能不會被浪費。

而且因為 React 是先產生 Virtual DOM(一份存在記憶體裡的草稿),再決定怎麼更新真正的畫面,這表示 React 不一定要跟瀏覽器綁在一起。

只要把「更新真正畫面」這一步換掉,React 就可以被用在不同的環境——在瀏覽器裡就更新網頁的 DOM,在手機裡就更新 App 的原生元件(這就是 React Native 的原理),甚至在伺服器上也可以用 React 來產生 HTML。

React 以組件(Component)為單位開發

React 的開發方式是把畫面拆成一個一個的 組件(Component) 。

你可以把組件想像成一塊塊的積木。

每一塊積木都是獨立的,有自己的資料、自己的狀態、自己的行為。

比如一個「按讚按鈕」就是一個組件,一個「留言區」也是一個組件。

每個組件會有這些東西:

Props(屬性)——從組件外部傳進來的資料

例如一個「貼文」組件要顯示讚數,這個讚數不是組件自己產生的,而是外部傳進來的。用程式的寫法來看就是 likeCount = 5,這個 5 就是透過 Props 傳進來的資料。

State(狀態)——組件內部自己管理的資料

例如一個「按讚按鈕」組件需要記住「目前的使用者有沒有按過讚」,這個資訊只有按鈕自己需要知道,不需要從外部傳進來。用程式的寫法來看就是 isLiked = true(按過讚)或 isLiked = false(沒按過讚)。

開發 React 其實就是在開發一個一個組件,再把它們像積木一樣組合起來,拼成完整的畫面。

因為每個組件是獨立的,你可以在不同的頁面重複使用同一個組件,也不用擔心改了 A 組件會影響到 B 組件。

jQuery 思維 vs React 思維:開發方式有什麼差別?

如果你之前是用 jQuery 開發的,轉換到 React 最需要改變的其實是思維方式。

jQuery 思維:直接動手改畫面

jQuery 的開發流程是這樣的:

  1. 從畫面上的某個元素裡取出資料
  2. 修改這份資料
  3. 再把新的資料塞回去畫面上的元素裡
// jQuery 思維:直接操作畫面上的元素

// 1. 去畫面上找到名叫 "like-count" 的元素,取出目前的讚數
從 #like-count 取出數字 → currentLikes = 5

// 2. 把讚數加一
currentLikes = 5 + 1 = 6

// 3. 再回到畫面上,把 "like-count" 元素裡的數字改成 6
把 #like-count 的內容從 5 改成 6

這樣做最大的問題是:你的程式跟畫面結構嚴重綁定。

注意上面的流程——每一步都是靠「元素的名字」(like-count)去找到元素、操作元素。

假設有一天,另一個同事覺得這個名稱不好,把它改成了 post-likes:

// 改名之前
畫面上有一個元素,名字叫 "like-count",裡面顯示 5

// 改名之後(同事改了名字)
畫面上有一個元素,名字叫 "post-likes",裡面顯示 5

這時候程式裡還是在找「名叫 like-count 的元素」,但畫面上已經沒有這個名字了,按讚功能直接壞掉。

更麻煩的是,在 jQuery 的開發方式裡,任何地方都可以用 like-count 這個名字來操作這個元素。

按讚功能的程式裡用了、收回讚的程式裡也用了、通知欄更新的程式裡也用了,甚至可能半年前某個已經離職的同事,在某個你不知道的檔案裡也用了。

這些程式碼散落在專案的各個角落,沒有任何機制可以幫你自動找出「到底有哪些地方用了 like-count 這個名字」。

你只能靠全域搜尋一個一個去找,每一個都要手動改掉,漏掉任何一個就是一個 bug。

React 思維:修改資料,畫面自動更新

React 的開發流程完全不同:

  1. 寫好畫面的樣子 ——告訴 React「讚數要顯示在按鈕裡面」
  2. 寫好事件處理 ——告訴 React「按鈕被按下去的時候,把讚數加一」
  3. 剩下的交給 React ——React 自動根據最新的讚數重新更新畫面

你不用自己去找元素、也不用自己去改元素,你只要把「畫面長什麼樣」和「什麼操作會改什麼資料」寫清楚就好。

// React 思維:只管資料,畫面交給 React

// 第一步:宣告資料
資料:likes = 0

// 第二步:寫好畫面的樣子
畫面:一個按鈕,裡面顯示「讚 {likes}」

// 第三步:寫好事件處理
當按鈕被按下去 → 把 likes 從 0 更新成 1

// 剩下的交給 React:
// React 偵測到 likes 變了,自動把按鈕上的文字從「讚 0」更新成「讚 1」

注意,在 React 裡你完全不需要去「找到某個元素然後改它」。

你只需要修改資料(把 likes 更新成新的值),React 就會自動幫你更新畫面。

這樣做的好處是:你可以自由地調整畫面的結構和位置,完全不用擔心程式會壞掉。

因為你的程式只跟資料有關,跟畫面的結構無關。

再加上每個組件都是獨立封裝的,其他組件無法直接存取你組件內部的內容,所以你不用擔心「改了這邊會壞那邊」。

React 特色重點整理

回顧一下這篇文章的內容。

React 不是一個什麼都包的框架,它只專注在一件事:把資料變成畫面。其他功能像頁面跳轉、資料管理,你可以根據需求自由搭配其他工具。

在建構畫面的方式上,React 也跟其他框架不同——它不用模板語法,而是直接用 JavaScript,讓你不需要額外學一套新語言。

當資料改變的時候,React 採用單向資料流的方式來更新畫面。你主動修改資料,React 自動幫你更新對應的畫面,而且只更新真正有變化的部分,不浪費效能。

整個開發過程是以組件為單位,每個組件獨立封裝、可以重複使用,不用擔心改了 A 會影響到 B。

如果要用一句話總結 jQuery 跟 React 最大的差別:jQuery 是「你親自去找元素、改元素」,React 是「你負責管資料,畫面的事情交給 React」。

理解了這些特色和思維之後,接下來在學 React 語法的時候,你就會更清楚它為什麼要這樣設計。

目前還沒有留言,成為第一個留言的人吧!

發表留言

留言將在審核後顯示。

JavaScript

目錄

  • React 只做 View:它跟 MVC 框架有什麼不同?
  • React 不用模板語法,只用 JavaScript
  • React 單向資料流:資料變了,畫面自動更新
  • React 以組件(Component)為單位開發
  • Props(屬性)——從組件外部傳進來的資料
  • State(狀態)——組件內部自己管理的資料
  • jQuery 思維 vs React 思維:開發方式有什麼差別?
  • jQuery 思維:直接動手改畫面
  • React 思維:修改資料,畫面自動更新
  • React 特色重點整理