问题
想象一下,您有一个带有数据库侦听器的屏幕,该侦听器是在 useEffect 中创建的,并且此侦听器的目的是增加屏幕中的计数器,如下所示:
(只使用 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 钩子和修改后的状态作为依赖)
useEffect(() => {
// ... the same stuff
}, [magazinesCounter]);
但是这样,我们将进入无限循环,因为将重新创建侦听器,并且
if (change.type === "added") {
_magazinesCounter += 1;
}
...
setMagazinesCounter(_magazinesCounter);
将被再次执行,并再次......
Pd:另外,将handleMagazinesChanges 函数包装在useCallback 中,并以magazinesCounter 作为依赖项,然后将该函数作为依赖项传递给useEffect,将具有相同的效果...
那么,我该如何解决这种情况呢?我知道,如果我们用 useRef 对相同数据使用辅助引用,我们可以成功执行此操作,避免无限循环。但是,有没有其他更好的方法来做到这一点?我的意思是,没有状态 + 对最新数据的引用:
(无依赖的 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();
}
}, []);
}
有任何想法吗?谢谢你。
Pd:也许这是要走的路,但我想有更好的方法而不创建辅助变量。