簡體   English   中英

為什么 Map 在嚴格模式下使用 setTimeout 和 React 更新兩次

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM