前言
還記得我一開始學習 React 時,總是習慣性地調整依賴陣列來解決問題,想當然爾地認為:「反正只要控制好依賴,Effect 就會按照我想要的次數執行」。但隨著開發經驗的累積,漸漸明白到這樣的思維其實不太正確。
這種做法雖然在短期內看似解決了問題,但往往會埋下一些難以發現的 bug。今天就讓我來分享一下,在實務上我們該如何處理 Effect 的依賴問題。
Effect 依賴的本質
在深入討論之前,我們必須先理解一個重要的概念:Effect 的依賴是由程式碼本身決定的,而不是由我們主觀決定想要執行幾次。這就像是在寫數學公式,如果公式中用到了某個變數,那這個變數就必然會影響結果。
讓我們看一個簡單的例子:
1 2 3 4 5 6 7 8
| function ChatRoom({ roomId }) { useEffect(() => { const connection = createConnection(roomId); connection.connect(); return () => connection.disconnect(); }, [roomId]); }
|
如何移除不必要的依賴?
當我們發現 Effect 因為某些依賴而過度執行時,應該從調整程式碼結構開始著手,而不是強制忽略這些依賴。以下分享幾個實用的技巧:
1. 確認是否真的需要使用 Effect
很多時候,我們其實不需要使用 Effect。特別是在處理事件回應時,直接使用事件處理函式會是更好的選擇:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| function Form() { useEffect(() => { if (submitted) { api.submitForm(data); } }, [submitted]); }
function Form() { function handleSubmit() { api.submitForm(data); } }
|
2. 將相關邏輯移至 Effect 內部
如果某個依賴項(特別是物件或函式)造成不必要的重新執行,考慮將它移到 Effect 內部:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| function ChatRoom({ serverUrl, roomId }) { const options = { serverUrl, roomId };
useEffect(() => { const connection = createConnection(options); }, [options]);
function ChatRoom({ serverUrl, roomId }) { useEffect(() => { const options = { serverUrl, roomId }; const connection = createConnection(options); }, [roomId, serverUrl]); }
|
3. 從物件中提取基本型別的值
當從 props 收到物件時,可以先解構出實際需要的值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| function ChatRoom({ options }) { useEffect(() => { const connection = createConnection(options); }, [options]);
function ChatRoom({ options }) { const { roomId, serverUrl } = options; useEffect(() => { const connection = createConnection({ roomId, serverUrl }); }, [roomId, serverUrl]); }
|
重要提醒
在處理 Effect 依賴時,有幾點特別要注意:
- 不要忽視 ESLint 的警告:這些警告通常代表潛在的問題,應該認真看待
- 依賴陣列反映程式碼的實際需求:它不是用來控制執行時機,而是用來確保同步機制的正確性
- 重構優於強制:如果發現依賴太多,應該思考如何重構程式碼,而不是強制移除依賴
總結
理解並正確處理 Effect 的依賴關係,是寫出優質 React 程式碼的關鍵之一。記住,當我們遇到依賴相關的問題時,應該從調整程式碼結構開始著手,而不是試圖透過修改依賴陣列來「控制」Effect 的行為。這樣不只能讓程式碼更容易維護,也能避免許多潛在的問題。