react
在 Hook 出現(xiàn)后,React 的函式元件 (Function Component) 逐漸成為主流。關(guān)于函式元件,最常見的問題之一,便是「為什么 React 的函式元件需要是純函式 (pure function)?」。本篇將以第一人稱的方式,擬答這個問題。 什么是純函式 (pure function)?
純函式是指帶有以下兩個主要特點的函式,第一是「只要有相同的輸入,就會有相同的輸出」;第二則是它不會改變函式以外的存在,換句話說不會有副作用 (side effects)。 舉例來說,f(x) = 2x?這個函式,只要輸入的 x 是 1,輸出的結(jié)果就會是 2;如果輸入的 x 是 2,輸出的就會是 4。不管呼叫多少次,輸出都會是一樣的,這就滿足純函式的第一個要件。相反地,假如函式當(dāng)中有?Math.random()?這類隨機(jī)性的運(yùn)算,會讓每次的輸出不一定,就不能稱為純函式。 沒有副作用,不改變函式以外的存在,則可以看到下面的例子 (推薦再回答這題時可以舉例,會更好說明)。當(dāng)本來在外的?guest?變數(shù),因為?getCup?函式改變,我們就不能稱?getCup?這個函式為純函式。
let
guest
=
1
; function
sayHi
(message)
{ guest = guest +
1
;
return
`${message} 跟 ${guest} guests `; } 為什么 React 的函式元件需要是純函式 (pure function)?
React 的函式元件之所以需要是純函式,是因為當(dāng)函式如果不純 (impure),會讓渲染出的畫面不穩(wěn)定,可能出現(xiàn)我們預(yù)期外的 UI 呈現(xiàn)。白話來說,就是比較容易造成 bugs。 如果每次的輸入,會有不同的輸出,那會讓 UI 的呈現(xiàn)非常不穩(wěn)定。以下面的程式碼為例,如果我們想要依據(jù)客人的人數(shù),來準(zhǔn)備巧克力派的食材,當(dāng)有隨機(jī)數(shù)出現(xiàn),每次傳入的客人數(shù)相同,可能會有不同的食材數(shù)量,這假如出現(xiàn)在食譜網(wǎng)站,那會是很不理想的 bug。 function
ChocolatePie
({ guestNum })
{
const
milkNum
=
guestNum * Math.floor(Math.random() *
10
)
const
chocolateNum
=
guestNum *
2
return
(
// 如果實際渲染這三個元件,同樣的 guestNum 會渲染出不同內(nèi)容
3 } />
3 } />
3 } />
如果有副作用,也將會造成不穩(wěn)定的 bugs。以下面來自 React 官方范例的程式碼來說,如果更動到了?Cup?元件外的?guest?,將會導(dǎo)致,即使渲染同一個?Cup?元件,卻渲染出不同內(nèi)容。這樣的 bug 也是不理想的。
let guest = 0 ;
function Cup () {
// Bad: changing a preexisting variable!
guest = guest + 1 ;
return for guest #{guest};
}
// 如果渲染下面這三個 Cup 元件,會有不同的結(jié)果
在 React 常見的函式,除了函式元件,也有?setState、context?。在使用它們時,都要確保是純函式。舉例來說,如果作為輸入傳進(jìn)去元件的?props,如果傳入同樣的?props?卻有不同的結(jié)果,就會造成不穩(wěn)定的 bugs。同樣地,當(dāng)我們要改變某個狀態(tài),如果直接去改變值,而不是?setState?,會造成副作用,這也會容易產(chǎn)生 bugs。
要在 React 避免不小心犯了這類錯誤,可以很簡單地使用嚴(yán)格模式 (Strict Mode)。當(dāng)我們開啟嚴(yán)格模式后,React 在渲染每個元件時,都渲染兩次;只要是不純的函式,就很可能在兩次渲染出現(xiàn)不同結(jié)果,這可以讓我們更偵測出是哪里出問題。
Tea cup