Jeff的隨手筆記

學習當一個前端工程師

0%

『Day 17』從命令式到宣告式:React 的開發思維轉變

前言

在前面的文章中,我們討論了許多 React 的基礎觀念,像是元件、JSX、Props 等等。今天想跟大家分享一個比較不一樣的主題:React 開發思維的轉變。

這個轉變不只改變了我們寫程式的方式,更重要的是改變了我們思考問題的角度。

命令式vs宣告式

我們用一個生活化的解釋讓大家更了解命令式(Imperative)和宣告式(Declarative)

想像一下你正在計程車上,你會怎麼跟司機說你要哪裡?

命令式的方式可能是:
「往前開三個路口、右轉、開兩個路口後左轉、在第二個巷子右轉…」

宣告式的方式則是:
「我要去台北車站」

這兩種表達方式的差異,正好反映了程式開發中的命令式和宣告式的差別。

  • 命令式:「一步步地指示程式應該做什麼(操作 DOM)。」
  • 宣告式:「描述我們想要的結果,讓 React 決定怎麼實現(透過虛擬 DOM)。」

從傳統 DOM 操作到 React

讓我們來看看實際的程式碼範例。假設我們要實作一個表單提交的功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 傳統的命令式寫法
const form = document.getElementById('myForm');
const button = form.querySelector('button');
const loading = document.getElementById('loading');
const error = document.getElementById('error');

form.onsubmit = function(e) {
e.preventDefault();
button.disabled = true;
error.style.display = 'none';
loading.style.display = 'block';
};

在 React 中,我們會這樣寫:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function SubmitForm() {
const [isSubmitting, setIsSubmitting] = useState(false);

const handleSubmit = (e) => {
e.preventDefault();
setIsSubmitting(true);
};

return (
<form onSubmit={handleSubmit}>
<button disabled={isSubmitting}>提交</button>
{isSubmitting && <div>讀取中...</div>}
{!isSubmitting && error && <div>錯誤訊息</div>}
</form>
);
}

你有發現差異嗎?React 的寫法更像是在描述我們想要的結果,而不是一步步指示應該怎麼做。

這種方式的好處在於 React 會自動根據狀態更新 DOM,開發者不需要手動追蹤狀態變化,也能更方便地重用元件。

實戰案例:

為了更具體地理解宣告式開發的流程,讓我們用一個簡單的計數器來示範。

這個計數器有增加和減少功能,且數值不能小於 0。

在開始coding之前,我們會先規劃好整個開發流程:

首先是定義所有可能的狀態及觸發條件:

可能會有哪些狀態:

  • 初始狀態(count = 0)
  • 可以減少的狀態(count > 0)
  • 不能減少的狀態(count = 0)

什麼動作會改變這些狀態:

  • 點擊增加按鈕會讓 count 增加
  • 點擊減少按鈕會讓 count 減少(但不能小於 0)

有了這些規劃後,我們就可以開始實作了。

使用 useState 管理狀態

先用 useState 來管理計數器的值:

1
const [count, setCount] = useState(0);

這時要特別注意,避免建立多餘的狀態。比如「可以減少的狀態」這個狀態,其實可以直接從 count 推導出來:

1
2
3
4
5
6
// ✅ 推薦的寫法:直接從 count 推導
const canDecrease = count > 0;

// ❌ 不建議的寫法:額外的狀態
const [canDecrease, setCanDecrease] = useState(false);

邏輯組合

最後,把這些邏輯組合起來,完成我們的計數器元件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function Counter() {
const [count, setCount] = useState(0);
const canDecrease = count > 0;

return (
<div>
<h2>計數器:{count}</h2>
<button onClick={() => setCount(prev => prev + 1)}>
增加
</button>
<button
onClick={() => canDecrease && setCount(prev => prev - 1)}
disabled={!canDecrease}
>
減少
</button>
</div>
);
}

這個例子很好地展示了宣告式開發的特點:我們先定義好想要的狀態和行為,然後讓 React 來處理實際的 DOM 更新。這樣的程式碼不只容易理解,也更容易維護。

總結

從命令式到宣告式的轉變,不僅讓我們的程式碼更容易維護,也讓開發思維更加清晰。在實作 React 應用時,建議遵循以下步驟:

  1. 先規劃所有可能的狀態與行為,確保邏輯清晰。
  2. 將狀態與 UI 的關係明確化,專注於描述「畫面應該怎麼呈現」。
  3. 避免建立多餘的狀態,善用推導方式簡化邏輯。

透過這些最佳實踐,我們能更好地處理複雜的 UI,讓程式碼既高效又容易維護。