我的錯!!!我從 WBC 熱身賽一路看到現在(3/11),每天中午晚上都看….我錯了!但在讓我看完整個賽程吧,會盡力完成目標的,雖然已經把1天的目標換成了2天完成了…
在當初設計學習目標時完全忘記了Pure Functions,是在看到官方文件後才回想起來有這個東西,但可能真的是當初讀得太不認真了完全沒有什麼印象,看來需要好好地複習一下。
什麼是Pure Function?
Pure functions 指的是在程式中不會有副作用(side effect)的函式。
它的特性是在相同輸入下會產生相同的輸出,且不會對外部的變數或狀態產生任何改變。
這樣的函式對於測試、重複使用、並行執行等都非常有利,並且能夠使程式更加容易理解和維護。在 React 中,Pure functions被廣泛應用在組件的開發和渲染中,因為這樣可以確保渲染結果的穩定性和一致性。
簡單來說,一個 function 只要符合以下兩個條件:
- 相同的 input,永遠都輸出相同的 output。
- 沒有產生 side effect。跟其他function不會互相干擾,不會修改/引用/存取或是依賴到到外部變數,但是當作參數傳入是可以的。
我們就可以把這個 function 稱為 Pure Function。
以下我們來用code來解釋這兩的條件:
相同的 input,永遠都輸出相同的 output。(Same inputs, same output.)
1 | ✅ 符合條件 |
沒有產生 side effect。
先來解釋一下名詞,side effect 中文翻譯成副作用。
side effect 指的就是在執行 function 時,該 function 的作用會影響到這個function 以外的資料,那麼『會影響到該 function 之外』的這個行為,就叫做 side effect。
聽到副作用這個詞感覺好像是一個很糟糕的狀況,其實並不是。在程式當中,side effect 單純就只是描述在寫 function 時有可能會出現的情況或是現象而已。
我們來看一下案例:
1 | let counter = 0; |
以上這個例子中,increment() function 會產生副作用,因為它改變了一個外部的變數 counter 的值。所以,這個 function 不是 pure function。
另外,像是使用 Math.random() 或是 Date.now() 這種會產生隨機數或是即時時間的 function,也都是有副作用的,因為它們的輸出不是固定的,會隨著時間或是機器而有所不同。
因此,如果要改變這個案例的輸出結果,我們可以給它一個props:
1 | let counter = 0; |
加入參數 counter 來取代外部變數就可以讓這個 function 變成 pure function。
在 React 中,有三個輸入可以在渲染時讀取:props, state 和 context。您應該始終將這些輸入視為只讀。
當我們希望對用戶輸入做出更改時,應該使用 state 而不是寫入變數。在元件渲染時,永遠不應該更改預先存在的變量或物件。
Local mutation(局部突變):
在上面的例子中,問題是元件在渲染時改變了一個已存在的變量。這通常被稱為“突變”。
Pure Function 不會改變函數範圍之外的變數或在調用之前創建的 object — — 這會讓它們變『不純』!
但是,在渲染時更改剛剛創建的變數和物件是完全可以的。
1 | function Cup({ guest }) { |
如同上面,我們創建了一個名為 cups 的空陣列,然後使用 for 迴圈將 12 個 Cup 元件推送到 cups 陣列中。最後,該函式將 cups 陣列返回。這段程式碼的作用是創建一個 TeaGathering 元件,該元件包含 12 個 Cup 元件。由於 Cup 元件是純函式,因此在渲染期間不會產生副作用。因此,這種方法可以安全地使用。
可能發生副作用的地方
在功能編程中,非常重視純淨性,但在某些時候,必須進行某些變更。
這些變更例如更新屏幕、開始動畫、更改數據,稱為副作用。
它們是在渲染期間“旁邊發生”的事情,而不是在渲染期間發生的事情。
在 React 中,副作用通常屬於事件處理函式。事件處理函式是 React 在執行某些操作時運行的函式,例如當點擊按鈕時。即使事件處理函式是在元件內部定義,它們也不會在渲染期間運行!因此,事件處理函式不需要是純函式。
如果已經盡可能使用了所有其他方法,仍然無法使用正確的事件處理函式,我們可以使用 useEffect
將其添加到返回的 JSX 中。這告訴 React 稍後在渲染之後,允許副作用執行它。然而,這種方法應該是您最後的手段。
常見的副作用但不限於此:
- 進行 HTTP request
- Mutating data
- Printing to a screen or console
- 操作 DOM
- Math.random()
- 取得當前時間