異常代碼
import React, { useState, useEffect } from 'react';
const App = () => {
const [arr, setArr] = useState([0]);
useEffect(() => {
console.log(arr);
}, [arr]);
const handleClick = () => {
Promise.resolve().then(() => {
setArr([...arr, 1]); // 此時賦值前 arr 為:[0]
})
.then(() => {
setArr([...arr, 2]); // 此時賦值前 arr 為舊狀態(tài)仍然為:[0]
});
}
return (
<>
<button onClick={handleClick}>change</button>
</>
);
}
export default App;
上面代碼,App 組件實際也是個閉包函數(shù),handleClick 里面引用著 arr,第一次 setArr 后 arr 的值確實更新了,我們也可以在下面截圖中看到,但此時 handleClick 事件處理函數(shù)作用域還是舊的,里面引用的 arr 仍然為舊的,導(dǎo)致第二次 setArr 后結(jié)果為 [0, 2]:
解決方案一
將上述代碼使用第二種(回調(diào))方式傳參
const handleClick = () => {
Promise.resolve().then(() => {
setArr(prevState => [...prevState, 1]); // 這里也可以不改,使用 setArr([...arr, 1]); 因為這里不需要獲取最新狀態(tài)
})
.then(() => {
setArr(prevState => [...prevState, 2]); // 這里必須改成回調(diào)函數(shù)傳參方式,否則會讀取舊狀態(tài),導(dǎo)致異常
});
}
解決方案二
利用 ref
import React, { useState, useRef, useEffect } from 'react';
const App = () => {
const [arr, setArr] = useState([0]);
let ref = useRef();
useEffect(() => {
ref.current = arr;
console.log(arr);
});
const handleClick = () => {
Promise.resolve().then(() => {
const now = [...ref.current, 1];
ref.current = now;
setArr(now);
})
.then(() => {
setArr([...ref.current, 2]);
});
}
return (
<>
<h1>{arr.toString()}</h1>
<button onClick={handleClick}>change</button>
</>
);
}
export default App;
官網(wǎng)中的一段話:如果你刻意地想要從某些異步回調(diào)中讀取 最新的 state,你可以用 一個 ref 來保存它,修改它,并從中讀取。