Jeff的隨手筆記

學習當一個前端工程師

0%

『新手學習React』- React Basice_Pure Functions

我的錯!!!我從 WBC 熱身賽一路看到現在(3/11),每天中午晚上都看….我錯了!但在讓我看完整個賽程吧,會盡力完成目標的,雖然已經把1天的目標換成了2天完成了…

在當初設計學習目標時完全忘記了Pure Functions,是在看到官方文件後才回想起來有這個東西,但可能真的是當初讀得太不認真了完全沒有什麼印象,看來需要好好地複習一下。

什麼是Pure Function?

Pure functions 指的是在程式中不會有副作用(side effect)的函式。

它的特性是在相同輸入下會產生相同的輸出,且不會對外部的變數或狀態產生任何改變。

這樣的函式對於測試、重複使用、並行執行等都非常有利,並且能夠使程式更加容易理解和維護。在 React 中,Pure functions被廣泛應用在組件的開發和渲染中,因為這樣可以確保渲染結果的穩定性和一致性。

簡單來說,一個 function 只要符合以下兩個條件:

  1. 相同的 input,永遠都輸出相同的 output。
  2. 沒有產生 side effect。跟其他function不會互相干擾,不會修改/引用/存取或是依賴到到外部變數,但是當作參數傳入是可以的。

我們就可以把這個 function 稱為 Pure Function。

以下我們來用code來解釋這兩的條件:

相同的 input,永遠都輸出相同的 output。(Same inputs, same output.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
✅ 符合條件
function add(value1, value2) {
return value1 + value2;
}

add(1, 2); // 3
add(3, 5); // 8
add(4, 6); // 10
//input是固定,return永遠都同一個結果

❌ 不符合條件
function now() {
return new Date();
}
//每次出來的時間都會不一樣

沒有產生 side effect。

先來解釋一下名詞,side effect 中文翻譯成副作用。

side effect 指的就是在執行 function 時,該 function 的作用會影響到這個function 以外的資料,那麼『會影響到該 function 之外』的這個行為,就叫做 side effect。

聽到副作用這個詞感覺好像是一個很糟糕的狀況,其實並不是。在程式當中,side effect 單純就只是描述在寫 function 時有可能會出現的情況或是現象而已。

我們來看一下案例:

1
2
3
4
5
6
7
8
9
10
11
12
let counter = 0;

function increment() {
counter += 1;
return counter;
}

increment(); // 1
increment(); // 2
increment(); // 3
//每次呼叫後counter值都會改變,所以不符合

以上這個例子中,increment() function 會產生副作用,因為它改變了一個外部的變數 counter 的值。所以,這個 function 不是 pure function。

另外,像是使用 Math.random() 或是 Date.now() 這種會產生隨機數或是即時時間的 function,也都是有副作用的,因為它們的輸出不是固定的,會隨著時間或是機器而有所不同。

因此,如果要改變這個案例的輸出結果,我們可以給它一個props:

1
2
3
4
5
6
7
8
9
10
let counter = 0;

function increment(counter) {
return counter + 1
}

increment(0); // 1
increment(1); // 2
increment(2); // 3

加入參數 counter 來取代外部變數就可以讓這個 function 變成 pure function。

在 React 中,有三個輸入可以在渲染時讀取:props, state 和 context。您應該始終將這些輸入視為只讀。

當我們希望對用戶輸入做出更改時,應該使用 state 而不是寫入變數。在元件渲染時,永遠不應該更改預先存在的變量或物件。

Local mutation(局部突變):

在上面的例子中,問題是元件在渲染時改變了一個已存在的變量。這通常被稱為“突變”。

Pure Function 不會改變函數範圍之外的變數或在調用之前創建的 object — — 這會讓它們變『不純』!

但是,在渲染時更改剛剛創建的變數和物件是完全可以的。

1
2
3
4
5
6
7
8
9
10
11
function Cup({ guest }) {
return <h2>Tea cup for guest #{guest}</h2>;
}

export default function TeaGathering() {
let cups = [];
for (let i = 1; i <= 12; i++) {
cups.push(<Cup key={i} guest={i} />);
}
return cups;
}

如同上面,我們創建了一個名為 cups 的空陣列,然後使用 for 迴圈將 12 個 Cup 元件推送到 cups 陣列中。最後,該函式將 cups 陣列返回。這段程式碼的作用是創建一個 TeaGathering 元件,該元件包含 12 個 Cup 元件。由於 Cup 元件是純函式,因此在渲染期間不會產生副作用。因此,這種方法可以安全地使用。

可能發生副作用的地方

在功能編程中,非常重視純淨性,但在某些時候,必須進行某些變更。

這些變更例如更新屏幕、開始動畫、更改數據,稱為副作用。

它們是在渲染期間“旁邊發生”的事情,而不是在渲染期間發生的事情。

在 React 中,副作用通常屬於事件處理函式。事件處理函式是 React 在執行某些操作時運行的函式,例如當點擊按鈕時。即使事件處理函式是在元件內部定義,它們也不會在渲染期間運行!因此,事件處理函式不需要是純函式。

如果已經盡可能使用了所有其他方法,仍然無法使用正確的事件處理函式,我們可以使用 useEffect 將其添加到返回的 JSX 中。這告訴 React 稍後在渲染之後,允許副作用執行它。然而,這種方法應該是您最後的手段。

常見的副作用但不限於此:

  1. 進行 HTTP request
  2. Mutating data
  3. Printing to a screen or console
  4. 操作 DOM
  5. Math.random()
  6. 取得當前時間