🚀 前端轉型心得:從 jQuery 到 React Hooks

更新於 發佈於 閱讀時間約 11 分鐘

軟體工程師職涯升級計畫啟動!立即預約職涯諮詢、履歷健檢或模擬面試👈,為您的加薪做好準備!

你是否曾經寫過一個 jQuery 專案,然後在一堆 callback、DOM 操作與邏輯糾纏中迷失方向?我也是。直到我遇見了 React,特別是 Hooks,才真正理解什麼是可維護、可擴展的前端架構。


🧮 一個簡單的計數器範例

從一個簡單的需求開始:點擊按鈕,數字會 +1。

jQuery 實作

html
複製編輯<!-- index.html -->
<button id="counter">0</button>
js
複製編輯// index.js
$('#counter').on('click', function() {
const current = parseInt($(this).html(), 10)
$(this).html(current + 1)
})

這段程式碼的流程如下:

  1. 讀取當前狀態值:$(this).html()
  2. 計算新值
  3. 更新 DOM

雖然簡單直觀,但隨著狀態變多、邏輯變複雜,jQuery 的管理方式就開始吃力了。


React Class Component 實作

jsx
複製編輯// Counter.js
import React from "react"

export class Counter extends React.Component {
constructor(props) {
super(props)
this.state = { count: 0 }
}

increment = () => {
this.setState({ count: this.state.count + 1 })
}

render() {
return (
<button onClick={this.increment}>
{this.state.count}
</button>
)
}
}
html
複製編輯<!-- index.html -->
<div id="root"></div>
<script type="text/babel">
ReactDOM.render(<Counter />, document.getElementById('root'))
</script>

React 的重點在於 狀態 (state)畫面 (UI) 的同步:只要更新 state,畫面就會自動重繪。


🔄 React 如何簡化 DOM 操作?

在 jQuery 中你得手動更新 DOM:

js
複製編輯$('#counter').html(nextCount)

而 React 中,只需要更新 state:

jsx
複製編輯setCount(count + 1)

React 會透過 Virtual DOM 比對差異並高效更新畫面。

這背後的理念是:UI 是 state 的投影 (UI = f(state))


🧩 元件化、封裝與維護性

jQuery 的問題

在 jQuery 中,邏輯分散在不同檔案,難以追蹤。例如:

html
複製編輯<!-- index.html -->
<button id="submitBtn">送出</button>

但行為邏輯可能在某個 .js 裡頭,找不到源頭也無從追蹤錯誤。

React 的組件化

React 把「樣板 + 行為」整合在同一個元件中,實現:

  • 封裝性:每個元件管理自己的狀態與邏輯。
  • 可重用性:元件可在不同頁面重複使用。
  • 可維護性:小型元件容易測試與理解。

🔁 重繪與 Virtual DOM:React 效能優化的關鍵

在使用 jQuery 等傳統 DOM 操作工具時,每當 UI 需要更新,我們都會直接操作實體 DOM(Real DOM)。這樣的方式在簡單應用上沒什麼問題,但在複雜應用中,頻繁的 DOM 操作將會大大拖慢效能。原因在於 DOM 操作非常昂貴,會觸發瀏覽器的重排(Reflow)與重繪(Repaint)

為了解決這個問題,React 採用了 Virtual DOM(虛擬 DOM) 的機制。它的基本概念是:

  1. React 不直接操作實體 DOM,而是先建立一棵Virtual DOM 樹(記憶體中的 UI 表現)
  2. 當 state 改變時,React 會根據新的 state 生成一棵新的 Virtual DOM 樹
  3. 接著,React 會比較新舊兩棵 Virtual DOM 的差異(diffing)
  4. 最後,只針對需要變更的部份去更新實體 DOM(這個步驟稱為 reconciliation

🔬 小範例說明:

假設你有一個簡單的列表 UI:

jsx
複製編輯function List({ items }) {
return (
<ul>
{items.map(item => <li key={item.id}>{item.text}</li>)}
</ul>
);
}

每次新增一個項目時,React 並不是將整個 <ul> 和全部 <li> 都重新渲染,而是:

  • 比對前後的 Virtual DOM
  • 偵測出「只有最後一個 <li> 是新增的」
  • 然後只更新新增的那個節點到實體 DOM

這種差異比較 + 精準更新的做法,比 jQuery 直接操作整個 DOM 要高效非常多


🧠 React Hooks:為什麼它會顛覆你的開發模式?

問題:Class Component 的混亂邏輯

js
複製編輯componentDidMount() {
document.title = `Clicked ${this.state.count}`
ChatAPI.subscribeToFriendStatus(this.props.friend.id, this.handleStatusChange)
}

常見狀況:

  • 不同邏輯被混在一個方法裡(如:設定 document.title + 訂閱事件)
  • 相同邏輯被拆散(如:初始化和清除邏輯分散在 DidMountWillUnmount

這讓程式碼難以理解、維護、測試。


Hooks 解法:關注點分離

jsx
複製編輯function FriendStatusWithCounter({ friend }) {
const [count, setCount] = useState(0)
const [isOnline, setIsOnline] = useState(null)

useEffect(() => {
document.title = `Clicked ${count} times`
}, [count])

useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline)
}

ChatAPI.subscribeToFriendStatus(friend.id, handleStatusChange)
return () => {
ChatAPI.unsubscribeFromFriendStatus(friend.id, handleStatusChange)
}
}, [friend.id])

return (
<div>
<p>{friend.name} is {isOnline ? 'Online' : 'Offline'}</p>
<button onClick={() => setCount(count + 1)}>{count}</button>
</div>
)
}

重點:

  • 每段邏輯用一個 useEffect,清晰可拆測
  • 不需要 this,不需要 bind
  • 更貼近 Functional Programming 思維

🧩 自訂 Hook:邏輯重用再進化

js
複製編輯function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null)

useEffect(() => {
const handleStatusChange = status => setIsOnline(status.isOnline)
ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange)
return () => ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange)
}, [friendID])

return isOnline
}

使用時只要:

js
複製編輯const isOnline = useFriendStatus(friend.id)

Hook 讓你不需要改變元件層級,就能重用有狀態的邏輯。


🧭 Hooks 優缺點比較

✅ 優點

  • 不再依賴 lifecycle 方法管理副作用
  • 更符合 Functional Paradigm
  • 可將邏輯封裝成可重用的 Hook
  • 新手學起來比 class 更直覺(不用理解 this

❗ 缺點

  • useEffect 容易誤用(沒設依賴陣列會導致無窮觸發)
  • 大型應用需注意效能與重繪次數
  • 過度抽象的 Hook 也可能變得難維護

🎥 推薦資源


🧾 結語

React 的出現,並不是因為 jQuery 不好,而是前端需求與複雜度提高後,我們需要新的解法

Hook 是 React 的一次里程碑,它重新定義了狀態邏輯、組件設計與程式碼組織方式。如果你還停留在 jQuery 或 class-based 的 React,現在是一個很棒的時機去認識 Hook!

留言
avatar-img
留言分享你的想法!
avatar-img
跨越國界的程式人生
2會員
37內容數
自學程式,現為網頁開發工程師,同時擔任線上課程講師,專注於幫助自學程式的開發者找到理想工作。熱愛技術與分享,致力於將複雜的概念轉化為實用知識,讓更多人踏入軟體開發的世界。
2025/06/19
求職過程中的經驗分享,涵蓋多家公司的面試流程、技術問題、薪資待遇以及最終結果。作者分享了準備面試的心得,並建議求職者持續學習、紀錄錯誤、瞭解市場趨勢,提升自身競爭力。
Thumbnail
2025/06/19
求職過程中的經驗分享,涵蓋多家公司的面試流程、技術問題、薪資待遇以及最終結果。作者分享了準備面試的心得,並建議求職者持續學習、紀錄錯誤、瞭解市場趨勢,提升自身競爭力。
Thumbnail
2025/06/19
這篇文章分享作者的面試經驗,提供求職者寶貴的建議,包括投遞策略、如何評估公司和職位,以及如何提升自身競爭力。文章涵蓋多家公司的面試過程細節,並提出將自身能力分配給求職標準的有效方法。
Thumbnail
2025/06/19
這篇文章分享作者的面試經驗,提供求職者寶貴的建議,包括投遞策略、如何評估公司和職位,以及如何提升自身競爭力。文章涵蓋多家公司的面試過程細節,並提出將自身能力分配給求職標準的有效方法。
Thumbnail
2025/06/17
這篇文章模擬了一段面試實戰,主題是找出陣列中出現頻率最高的 k 個元素。文章詳細介紹瞭解題思路,包括使用 Map 計算頻率和使用最小堆維持 top k 元素,並比較了不同方法的優缺點。最後,文章總結了面試技巧,以及這類題目在面試中的重要性。
Thumbnail
2025/06/17
這篇文章模擬了一段面試實戰,主題是找出陣列中出現頻率最高的 k 個元素。文章詳細介紹瞭解題思路,包括使用 Map 計算頻率和使用最小堆維持 top k 元素,並比較了不同方法的優缺點。最後,文章總結了面試技巧,以及這類題目在面試中的重要性。
Thumbnail
看更多
你可能也想看
Thumbnail
常常被朋友問「哪裡買的?」嗎?透過蝦皮分潤計畫,把日常購物的分享多加一個步驟,就能轉換成現金回饋。門檻低、申請簡單,特別適合學生與上班族,讓零碎時間也能創造小確幸。
Thumbnail
常常被朋友問「哪裡買的?」嗎?透過蝦皮分潤計畫,把日常購物的分享多加一個步驟,就能轉換成現金回饋。門檻低、申請簡單,特別適合學生與上班族,讓零碎時間也能創造小確幸。
Thumbnail
你好,在下最近在學習開發web,學了html css js,也得出一些心得,由於網路上已有許多教學,所以我會著重在如何開發出to do List,以及解釋我寫的程式碼。相關的教學我會直接貼網址。如果我有什麼地方出錯,或者是可以寫得更好,歡迎在下方留言,討論。 首先先介紹我的開發環境: 我用了vs
Thumbnail
你好,在下最近在學習開發web,學了html css js,也得出一些心得,由於網路上已有許多教學,所以我會著重在如何開發出to do List,以及解釋我寫的程式碼。相關的教學我會直接貼網址。如果我有什麼地方出錯,或者是可以寫得更好,歡迎在下方留言,討論。 首先先介紹我的開發環境: 我用了vs
Thumbnail
JavaScript30 傳送門:https://javascript30.com/ 寫到挑戰六覺得心累ㄌ,向來不是一個可以長久堅持好習慣的人,30 個挑戰聽起來很少,但如果要日復一日堅持下去其實好長r 😮‍💨 挑戰六透過 input 來 filter 從 api 拿回來的資料結
Thumbnail
JavaScript30 傳送門:https://javascript30.com/ 寫到挑戰六覺得心累ㄌ,向來不是一個可以長久堅持好習慣的人,30 個挑戰聽起來很少,但如果要日復一日堅持下去其實好長r 😮‍💨 挑戰六透過 input 來 filter 從 api 拿回來的資料結
Thumbnail
JavaScript30 傳送門:https://javascript30.com/ 挑戰5透過玩弄 flex-grow 屬性來操作網頁裡的卡片效果,看別人的成果:yhabib.github.io 本次學習心得: 製造過度效果延遲的方法:transition-delay V.S
Thumbnail
JavaScript30 傳送門:https://javascript30.com/ 挑戰5透過玩弄 flex-grow 屬性來操作網頁裡的卡片效果,看別人的成果:yhabib.github.io 本次學習心得: 製造過度效果延遲的方法:transition-delay V.S
Thumbnail
在程式任何地方都能修改各種react組件狀態的做法分享
Thumbnail
在程式任何地方都能修改各種react組件狀態的做法分享
Thumbnail
JavaScript30 傳送門:https://javascript30.com/ 透過 JS 控制 CSS 變數 今天的挑戰是要能透過滑動圖片上面的 <input type="range"> 來改變圖片的三個屬性。 以前在 CSS 裡面看到 var(--xxxx) 這種東西都很
Thumbnail
JavaScript30 傳送門:https://javascript30.com/ 透過 JS 控制 CSS 變數 今天的挑戰是要能透過滑動圖片上面的 <input type="range"> 來改變圖片的三個屬性。 以前在 CSS 裡面看到 var(--xxxx) 這種東西都很
Thumbnail
CSS 的繼承性是開發網頁樣式時的一個重要概念,它使得樣式設計更加靈活和高效,有助於提高程式碼的可讀性、一致性和可重用性,並加快開發速度,從而提供更好的開發體驗。
Thumbnail
CSS 的繼承性是開發網頁樣式時的一個重要概念,它使得樣式設計更加靈活和高效,有助於提高程式碼的可讀性、一致性和可重用性,並加快開發速度,從而提供更好的開發體驗。
Thumbnail
JavaScript 套件,頁碼 Pagination.js 搭配 axios API 請求範例
Thumbnail
JavaScript 套件,頁碼 Pagination.js 搭配 axios API 請求範例
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News