我useEffect()用來獲取 Firestore 快照并并行計算一個值:
const [counter, setCounter] = useState({ mona: 0, phil: 0 });
useEffect(() => {
onSnapshot(q, (snapshop) => {
setTasks(
snapshop.docs.map((doc) => {
if (doc.data().wer === "Mona") {
console.log("Mona 1"); // This get's executed as expected (e.g. 3 times)
setCounter({ ...counter, mona: counter.mona 1 });
}
if (doc.data().wer === "Phil") {
console.log("Phil 1"); // This get's executed as expected (e.g. 6 times)
setCounter({ ...counter, phil: counter.phil 1 });
}
return {
...doc.data(),
id: doc.id,
timestamp: doc.data().timestamp?.toDate().getTime(),
};
})
);
setLoading(false);
});
}, []);
useEffect(() => {
console.log({ counter }); //this get's executed only 2 times.
}, [counter]);
當console.log()內map()get 執行正確時,為什么 setCounter 不正確執行或更新計數器?
該console.log({ counter });BTW給不外乎:
{counter: {mona: 0, phil: 0}}
{counter: {mona: 0, phil: 1}}
uj5u.com熱心網友回復:
React 有時會批量更新狀態。這意味著您的所有呼叫都setCounter只會觸發一種效果。
此外,counter函式內部的值也會在函式結束時更新,因此您將丟失更新。
你應該做什么:
首先將回呼傳遞給
setCounter而不是使用的值counter。所以改變:setCounter({ mona: counter.mona, phil: counter.phil 1 });到:
setCounter(counter => ({ mona: counter.mona, phil: counter.phil 1 }));要強制多次呼叫 useEffect,您必須使用以下命令選擇退出批量更新
ReactDOM.flushSync:import { flushSync } from 'react-dom'; // ... flushSync(() => setCounter(counter => ({ mona: counter.mona, phil: counter.phil 1 })));通過這種方式,您
useEffect應該為計數器的每次更改而呼叫。顯然,這比批量更新效率低。
由于每次您想重新計算每次呼叫 onSnapshot 時的所有內容而不是簡單地修改當前值時,您都在重新加載整個資料集。
在這種情況下,您可以這樣做:
const newCounter = { mona: 0, phil: 0};
snapshop.docs.map((doc) => {
if (doc.data().wer === "Mona") {
console.log("Mona 1"); // This get's executed as expected (e.g. 3 times)
newCounter.mona = 1;
}
if (doc.data().wer === "Phil") {
console.log("Phil 1"); // This get's executed as expected (e.g. 6 times)
newCounter.phil = 1;
}
// ...
});
setCounter(newCounter);
因此,您只需計算結果并setCounter使用最終計數在回圈外呼叫一次。在這種情況下,您不需要讀取舊狀態,因為您從頭開始重新計算它。
您可以保留舊代碼并setCounter({mona: 0, phil: 0})在回圈外添加一個,但我相信這比計算 react 鉤子之外的值并僅呼叫setCounter一次效率低。
uj5u.com熱心網友回復:
您傳遞給的函式會useEffect關閉counter變數。
當您在商店中呼叫setCounter它時,它會更新counter,并且鉤子會重新呈現。效果掛鉤不會再次運行,因為沒有任何依賴項([]- 沒有任何依賴項)已更改。
下次onSnapshot觸發設定的事件處理程式時,它使用與counter上一次相同的值。這意味著counter.phil仍然0在效果鉤子內。您添加1到0 再次和呼叫setCounter但是這個值是一樣的前值。
由于counter這次沒有改變,第二個依賴于值的效果鉤子counter不會被觸發。
傳遞一個函式來setCounter獲取最近的值而不是原始的關閉值:
setCounter((latestCounter) => { ...latestCounter, phil: latestCounter.phil 1 });
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/369193.html
標籤:javascript 反应 使用效果 使用状态
上一篇:如何制作可啟動軟盤映像?
下一篇:為展平樹中的每個物件創建一個級別
