昨天在介紹 React 如何把畫面呈現在網站上的三個步驟,今天會再針對 state 更新後重新 render 更新畫面再做更多的延伸介紹。
今天的文章參考官方文件的:
當我們更新 state 後,會觸發 render,並且 React 會開始呼叫 component 進行 rendering。而這時候的 component 就會是一個會回傳 JSX 的函式,這個 JSX 就像是螢幕的快照(snapshot),會記錄當下 render 的 state 並計算出的 prop
、event handler
或區域變數等。React 接著更新畫面,使畫面與你回傳的快照相符。因為在一次 render 只會計算那一次,所以就算在我們的 handler
裡面使用多次 setter
來更新 state,React 都會根據當下 render 所擁有的資料去進行更新。就拿官方文件中的例子:
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>
</>
)
}
雖然我們在 onClick
裡面呼叫 setNumber
三次,但最後畫面更新完的數字仍然只有增加 1
,這是因為 handler
裡面的 number
在這一次 render 一直都會是 0
,所以就算呼叫三次,也只是把 0
變成 1
三次,而不會隨著呼叫次數遞增。它的 event handler 看起來就像是這樣:
<button onClick={() => {
setNumber(0 + 1);
setNumber(0 + 1);
setNumber(0 + 1);
}}>+3</button>
接下來再用另一個情境來解釋 state 的快照,那就是在我們的 handler
裡面設定計時器,讓我們點擊按鈕後過一段時間後再執行別的程式碼,藉此來看看畫面有何變化,一樣使用文章中的範例:
import { useState } from 'react';
export default function Counter() {
const [number, setNumber] = useState(0);
return (
<>
<h1>{number}</h1>
<button onClick={() => {
setNumber(number + 5);
setTimeout(() => {
alert(number);
}, 3000);
}}>+5</button>
</>
)
}
這段程式碼的功能,會是當按下按鈕後,更新 number
這個 state,並且在 3 秒後呼叫 alert
顯示 number
這個 state。大家也可以在按下按鈕前,想想看會產生什麼樣的結果。
答案揭曉,實際操作按下 +5
後,會發現畫面的數字變成 5
了,但經過三秒後,alert
執行的結果跳出提示,會顯示的是一開始的 0
。這再次說明了,在同一次 render 裡,state 變數的值永遠不會改變,就算它的 event handler 的程式碼是非同步的。
剛剛 onClick
的執行快照會是:
setNumber(0 + 5);
setTimeout(() => {
alert(0);
}, 3000);
當 React 透過呼叫 component 來替 UI「拍攝快照」時,state 的值「固定不變」,這是 React 的設定,所以不用擔心 state 在程式碼執行時有所異動。
但有沒有可能在重新 render 前就讀取最新的 state 呢?是可能的,這在明天的文章會進行介紹。
今天把 state 像是快照一樣的概念介紹給大家,希望可以讓大家多了解一點 state 的更新會發生什麼事,幫助以後在開發程式的時候可以更快知道 state 的更新是如何運作的。
今天的文章就介紹到這邊,感謝大家耐心地看完,如果有任何問題與建議歡迎都跟我說,明天見,晚安。