[英]Why does a callback in setTimeout have this == Window even in strict mode?
[英]Why does Map updated twice with setTimeout and React in Strict Mode
我有以下 React 組件:
App.tsx:
function App() {
const [countdownTimers, setCountdownTimers] = React.useState<
Map<number, number>
>(new Map([[1, 60]]));
useEffect(() => {
const timeoutId = setInterval(() => {
setCountdownTimers((prevState) => {
console.log(prevState);
for (const [timerKey, timer] of prevState) {
prevState.set(timerKey, timer - 1);
}
return new Map(prevState);
});
}, 1000);
return () => {
clearInterval(timeoutId);
};
}, []);
return <>{countdownTimers.get(1)}</>;
};
index.tsx
<React.StrictMode>
<App />
</React.StrictMode>
上面的代碼預計每秒從Map
中的所有值中減去1
。 但是由於StrictMode
它減去2
。 刪除<React.StrictMode>
解決了問題,但我想了解為什么StrictMode
僅在Map
時才會這樣做
你能告訴我為什么會這樣嗎?
在嚴格模式下,state 更新程序函數被調用兩次以嘗試檢測可能的錯誤。
你這里的代碼確實有一個有爭議的錯誤——你在這里改變了Map中現有的 state:
setCountdownTimers((prevState) => {
console.log(prevState);
for (const [timerKey, timer] of prevState) {
prevState.set(timerKey, timer - 1);
}
return new Map(prevState);
});
盡管您在返回時創建了一個新的 Map,但您仍在調用prevState.set
- 對其進行變異。 這意味着(嚴格的)state 更新程序第二次運行時,它看到的 Map(第二次在prevState
中)的值已經遞減了一次。
不要改變現有的 Map,而是立即創建新的 Map,並且只更改新的 Map。
function App() { const [countdownTimers, setCountdownTimers] = React.useState(new Map([[1, 60]])); React.useEffect(() => { const timeoutId = setInterval(() => { setCountdownTimers((prevState) => { const newMap = new Map(prevState); console.log(JSON.stringify([...newMap.entries()])); for (const [timerKey, timer] of prevState) { newMap.set(timerKey, timer - 1); } return newMap; }); }, 1000); return () => { clearInterval(timeoutId); }; }, []); return countdownTimers.get(1); }; ReactDOM.createRoot(document.querySelector('.react')).render(<React.StrictMode><App /></React.StrictMode>);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script> <div class='react'></div>
發生這種情況是因為 React 嚴格模式,它與Map
數據結構沒有任何關系。 根據文檔:
嚴格模式無法自動為您檢測副作用,但它可以通過使它們更具確定性來幫助您發現它們。 這是通過有意地重復調用以下函數來完成的:
Class 組件構造函數、渲染和 shouldComponentUpdate 方法
Class 組件 static getDerivedStateFromProps 方法
Function 組件機構
State 更新函數(setState 的第一個參數)
傳遞給 useState、useMemo 或 useReducer 的函數
本質上,傳遞給setCountdownTimers
setter 的回調被調用兩次,因此減去2
而不是1
。 它不應該發生在生產中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.