假设您有一个屏幕,其中包含一个在useEffect中创建的数据库侦听器,此侦听器的目的是在屏幕上增加一个计数器,如下所示:
function MyScreen(props) {
const [magazinesCounter, setMagazinesCounter] = useState(0);
const handleMagazinesChanges = (snapshot) => {
const changes = snapshot.docChanges();
let _magazinesCounter = magazinesCounter;
changes.forEach((change) => {
if (change.type === "added") {
_magazinesCounter += 1;
}
if (change.type === "removed") {
_magazinesCounter -= 1;
}
});
setMagazinesCounter(_magazinesCounter);
};
useEffect(() => {
const query = props.db.collection("content")
.where("type", "==", "magazine");
// Create the DB listener
const unsuscribe = query.onSnapshot(handleMagazinesChanges, (err) => {});
return () => {
unsuscribe();
}
}, []);
}
如您所见,这将不起作用,因为状态更新时不会重新创建useEffect的侦听器中使用的handleMagazinesChanges。
因此,我尝试解决了将MagazinesCounter作为对useEffect的依赖项传递的问题,如下所示:
useEffect(() => {
// ... the same stuff
}, [magazinesCounter]);
但是有了这个,我们将进入一个无穷循环,因为将重新创建侦听器,并且
if (change.type === "added") {
_magazinesCounter += 1;
}
...
setMagazinesCounter(_magazinesCounter);
将被再次执行...
Pd:同样,将handleMagazinesChanges函数包装在useCallback中,并将MagazinesCounter作为依赖项,然后将该函数作为依赖项传递给useEffect,将具有相同的效果...
那么,如何解决这种情况?我知道,如果我们使用useRef对相同的数据使用辅助引用,则可以成功执行此操作,从而避免了无限循环。但是,还有其他更好的方法吗?我的意思是,没有状态+对最新数据的引用:
// This works good, but is there any other better solution to this problem?
function MyScreen(props) {
const [magazinesCounter, setMagazinesCounter] = useState(0);
const magazinesCounterRef = useRef(magazinesCounter);
const handleMagazinesChanges = (snapshot) => {
const changes = snapshot.docChanges();
changes.forEach((change) => {
if (change.type === "added") {
magazinesCounterRef.current += 1;
}
if (change.type === "removed") {
magazinesCounterRef.current -= 1;
}
});
setMagazinesCounter(magazinesCounterRef.current);
};
useEffect(() => {
const query = props.db.collection("content")
.where("type", "==", "magazine");
// Create the DB listener
const unsuscribe = query.onSnapshot(handleMagazinesChanges, (err) => {});
return () => {
unsuscribe();
}
}, []);
}
有任何想法吗?谢谢。
帕德:也许这是要走的路,但是我想有一个更好的方法而不创建辅助变量。
为此,我有两个建议:
useEffect
以避免在每次渲染时重新创建函数在当前代码中使用它们:
function MyScreen(props) {
const [magazinesCounter, setMagazinesCounter] = useState(0);
useEffect(() => {
// Moved inside "useEffect" to avoid re-creating on render
const handleMagazinesChanges = (snapshot) => {
const changes = snapshot.docChanges();
// Accumulate differences
let difference = 0;
changes.forEach((change) => {
if (change.type === "added") {
difference += 1;
}
if (change.type === "removed") {
difference -= 1;
}
});
// Use the setState callback
setMagazinesCounter((currentMagazinesCounter) => currentMagazinesCounter + difference);
};
const query = props.db.collection("content")
.where("type", "==", "magazine");
// Create the DB listener
const unsuscribe = query.onSnapshot(handleMagazinesChanges, (err) => {});
return () => {
unsuscribe();
}
}, []);
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句