我具有以下useEffect函数,并尝试找到在卸载组件时清除此问题的最佳方法。
我认为最好遵循React docs的makeCancelable
,但是,取消诺言后,代码仍会执行。
const makeCancelable = (promise) => {
let hasCanceled_ = false;
const wrappedPromise = new Promise((resolve, reject) => {
promise.then(
val => hasCanceled_ ? reject({isCanceled: true}) : resolve(val),
error => hasCanceled_ ? reject({isCanceled: true}) : reject(error)
);
});
return {
promise: wrappedPromise,
cancel() {
hasCanceled_ = true;
},
};
};
//example useEffect
useEffect(() => {
const getData = async () => {
const collectionRef_1 = await firestore.collection(...)
const collectionRef_2 = await firestore.collection(...)
if (collectionRef_1.exists) {
//update local state
//this still runs!
}
if (collectionRef_2.exists) {
//update local state
//and do does this!
}
}
const getDataPromise = makeCancelable(new Promise(getData))
getDataPromise.promise.then(() => setDataLoaded(true))
return () => getDataPromise.cancel()
}, [dataLoaded, firestore])
我也尝试过const getDataPromise = makeCancelable(getData)
,但没有任何运气。代码执行正常,只是在卸载组件时未正确清理。
我还需要取消两个等待功能吗?
答案 0 :(得分:2)
在您的makeCancelable
函数中,您只是在承诺完成后检查hasCanceled_
的值(意味着getData
已完全执行):>
const makeCancelable = (promise) => {
let hasCanceled_ = false;
const wrappedPromise = new Promise((resolve, reject) => {
// AFTER PROMISE RESOLVES (see following '.then()'!), check if the
// react element has unmount (meaning the cancel function was called).
// If so, just reject it
promise.then(
val => hasCanceled_ ? reject({isCanceled: true}) : resolve(val),
error => hasCanceled_ ? reject({isCanceled: true}) : reject(error)
);
});
return {
promise: wrappedPromise,
cancel() {
hasCanceled_ = true;
},
};
};
相反,在这种情况下,我建议您选择一个更简单,更经典的解决方案,并使用isMounted
变量创建所需的逻辑:
useEffect(() => {
let isMounted = true
const getData = async () => {
const collectionRef_1 = await firestore.collection(...)
const collectionRef_2 = await firestore.collection(...)
if (collectionRef_1.exists && isMounted) {
// this should not run if not mounted
}
if (collectionRef_2.exists && isMounted) {
// this should not run if not mounted
}
}
getData().then(() => setDataLoaded(true))
return () => {
isMounted = false
}
}, [dataLoaded, firestore])