在昨天的文章,介紹了 state 就像是螢幕快照一樣,一次 render 只會的 state 不會改變,所以我們如果進行三次 setNumber(number + 1)
所更新的 state 也只會有一次,因為這邊的 number
都是 0
。
import { useState } from 'react';
export default function Counter() {
const [number, setNumber] = useState(0);
return (
<>
<h1>{number}</h1>
<button onClick={() => {
setNumber(number + 1);
setNumber(number + 1);
setNumber(number + 1);
}}>+3</button>
</>
)
}
最後更新完顯示的就會是 1
,那如果我們同時寫上增加不同的數字會怎麼樣呢:
import { useState } from 'react';
export default function Counter() {
const [number, setNumber] = useState(0);
return (
<>
<h1>{number}</h1>
<button onClick={() => {
setNumber(number + 1);
setNumber(number + 2);
setNumber(number + 3);
}}>+3</button>
</>
)
}
最後會發現因為一開始的 state 都是 0
,但最後執行的會是 setNumber(0 + 3)
,所以顯示的值就會是 3
。會這樣執行就會講到另一個 React 更新 state 功能,批次更新(batch update)。
今天的文章參考官方文章的:
當我們在 handler
裡面執行 state 更新的時候,React 會等到所有在 handler
裡的程式碼跑過一次後再進行 state 的更新,之後在重新 render 畫面。這就像是餐廳服務員會等到客人點完餐(中間可以改變心意),再把點餐的內容傳到給廚師處理。
這樣的處理可以避免多次觸發 re-render,讓我們的應用程式可以跑得更快。不過 React 橫跨各 handler
來進行 batch 更新,每一次都會是獨立的,像是點擊按鈕。如果第一次按按鈕把表單(form)給關掉(disabled),第二次點擊的時候就不會送出,因為已經關掉了。
如果在下一次 render 前,就先更新 state 的值,譬如說在 handler
裡面,我們可以在 setter
裡面傳入一個根據前一個在序列(queue)裡的 state 計算出的更新後的 state 的 function,會寫成像是 setNumber(n => n + 1)
,這個意思就是會把 state 更新成前一個 state 值 + 1,因為回傳的是 n + 1
,我們也可以做其他處理再回傳。這樣的回傳 function 會告訴 React 對 state 進行處理而不是直接取代。
把我們前面的範例修改一下就會變成:
import { useState } from 'react';
export default function Counter() {
const [number, setNumber] = useState(0);
return (
<>
<h1>{number}</h1>
<button onClick={() => {
setNumber(n => n + 1);
setNumber(n => n + 1);
setNumber(n => n + 1);
}}>+3</button>
</>
)
}
這樣這次 +3 的按鈕按下去就會顯示 3
了。n => n + 1
這個傳進 setter
裡的 function,又叫做 updater function,他在執行的時候會做兩件事:
剛剛的範例寫成表格就會像是:
在這邊,updater function 也需要是一個 pure function,不能在裡面有其他 side effect,不然會發生非預期的錯誤。
在使用 pure function 的時候,參數是可以自己命名的,因為剛才是 setNumber
的 updater function 所以把使用的前一個 state 命名為 n
代表 number
,所以不是全部的 function 都是使用 n
當作參數。我自己的話因為是代表前一個,所以比較通用會使用 prev
代表前一個 state 的意思。可以跟團隊討論看看怎樣才是最適合的命名。
今天介紹了 state 的 batch update,跟 state updater function,希望有讓大家能了解更多關於 state 的更新。
今天的文章告一個段落了,感謝大家耐心地看完,如果有任何問題與建議歡迎跟我說,明天見,晚安。