前言
在 React 的開發過程中,好的狀態管理不只關乎程式碼是否容易理解,更直接影響到專案的可維護性與穩定性。還記得我在學習 React 時,當課程進度進入到 state 的部分,一開始覺得還蠻簡單的,直到後來要重構整個程式碼時才發現:原來不好的 state 設計會讓程式變得多麽難維護。那時候真的是被 state 管理搞得焦頭爛額。
今天我們就來看看 React 官方對於狀態設計的建議。相信這些原則不只能幫助我們寫出更好的程式碼,也能讓其他正在學習的夥伴少走一些彎路。
相關狀態要懂得「抱團」
在開發的初期,我常常會直覺地為每個需要追蹤的數值建立一個獨立的 state。但到最後才發現,當多個狀態總是一起更新時,分開管理可能導致程式碼難以維護。將相關狀態整合在一起,能使程式碼更簡潔、邏輯更清晰。
假設我們要追蹤滑鼠在畫面上的位置:
1 | function MouseTracker() { |
這樣寫雖然可以運作,但當我們把相關的狀態組織在一起時,程式碼會更容易理解和維護:
1 | function MouseTracker() { |
總結來說,將相關的狀態整合在一起不僅能減少重複更新的麻煩,也能讓程式碼的邏輯更直觀。
更新物件型態 State
React 的 setState
預設是完全取代舊的狀態,而非進行部分合併。這樣的設計是為了避免預設合併邏輯帶來的不確定性,因此需要我們手動操作。
因此當我們使用物件作為 state 時,更新的方式需要特別注意,不然很容易發生資料不見的問題。
讓我用一個實際的例子來說明:
1 | function UserProfile() { |
當我們點擊按鈕時,會發現畫面上只剩下名字,年齡和 email 都不見了!這是因為在 React 中,setState 不會幫我們合併物件,而是直接用新的物件取代舊的。
正確的做法是使用展開運算符(…)來保留其他欄位:
1 | // ✅ 正確的寫法 |
這樣寫有幾個好處:
- 透過展開運算符(
...
)保留原本的資料,避免不小心遺失其他欄位 - 程式碼的意圖更明確 - 我們可以清楚看到哪些是要保留的,哪些是要修改的部分
- 當物件結構變得更複雜時,這種更新模式依然可以保持程式碼的可維護性
這就是為什麼我們會想把相關的資料放在同一個物件裡面 - 既可以一次完整地保留所有需要的資料,又能清楚地表達程式的意圖。
說真的,我第一次寫 React 時也在這裡踩過地雷。看到資料莫名消失時,整個人都傻了:「蛤?我明明就只改個名字而已,怎麼其他資料都不見了?」這個經驗讓我更深刻理解到,在操作物件型態的 state 時,正確的更新方式能幫助我們避免很多意想不到的問題。
避免狀態矛盾
在處理表單或複雜的使用者互動時,我們經常需要追蹤多個相關的狀態。這時候很容易不小心製造出互相矛盾的狀態。舉個例子,假設我們在處理一個表單提交的流程:
1 | function FeedbackForm() { |
這樣的設計看似合理,但如果網路請求失敗了呢?我們可能會遇到 isSending
和 isSent
狀態不一致的問題。
更好的做法是使用單一的狀態來表達這個流程:
1 | function FeedbackForm() { |
避免不必要的 State
在實務上,我常看到開發者把可以從現有資料計算出來的值也放進狀態。這不只增加了程式碼的複雜度,更容易導致資料不同步的問題。
比方說,處理使用者的全名:
1 | // 不建議的做法 |
總結
好的狀態設計能讓我們的程式碼更容易維護,也能避免許多常見的錯誤。根據我的經驗,遵循以下原則能幫助我們寫出更好的 React 應用:
- 將相關的狀態組織在一起:減少重複更新,讓邏輯更清楚。
- 使用單一狀態來表示多個相關狀態:避免矛盾或不一致的狀態。
- 避免將可計算的值放入狀態:利用即時計算來減少狀態同步問題。
- 保持狀態結構扁平化:簡化狀態更新邏輯。
記住,在設計狀態時要追求簡單但不過度簡化。找到這個平衡點需要經驗的累積,但只要持續實踐這些原則,相信大家都能寫好 React 。