一個關於 useState 的誤解
本文寫於 2020 年 11 月 17 日
前兩天有人問了我一個問題,他有一段這樣的代碼:
function App() {
const [n, setN] = useState(0);
return (
<div>
<h1>{n}</h1>
<button onClick={() => setN((x) => x + 1)}>+1</button>
<button onClick={() => setTimeout(() => console.log(n), 3000)}>
log
</button>
</div>
);
}
如果他先點擊 “+1” 按鈕,再點擊 log 按鈕,控制台就會在 3s 后輸出 h1
內顯示的值——即 +1 后的數字。
但是如果他先 log,再點擊 “+1”,獲得的卻還是上一次的數值,並不是 h1
顯示的值。
這是為什么?
因為 setState 不是改變了 state 的值,而是有了一個新的 state。
React 重新執行了組件函數,將原來的值進行處理之后賦給了新的值——所以原來的值永遠是原來的值。
換個角度說,假設你有一個函數如下:
function foo() {
const a = 1;
}
如果 foo 執行了兩次,那么這兩次創建的 a 會是一個 a 嗎?當然不是呀。
此時在該函數里放一個閉包:
function foo() {
const a = 1;
setTimeout(() => consol.log(a), 1000);
}
第二次執行的 setTimeout 可能訪問到第一次執行時創建的 a 變量嗎?
因此,setTimeout
是在舊的函數里觸發的,3s 后讀取的就是舊的函數里的 n
值。
(完)