我对useEffect有问题。当我试图在onAuthStateChanged
之后获得用户的身份验证状态时,useEffect中的调用数量高得离谱。有时也会出现以下错误:
警告:无法对已卸载的组件执行React状态更新。这是一个非操作,但表示应用程序中存在内存泄漏。要修复此问题,请取消useEffect清理函数中的所有订阅和异步任务
这是用户登录/注册和注销后的日志量。也许我不太了解useEffect是如何工作的。以下是使用useEffect:的代码
useEffect(async () => {
let isCancelled = false;
await firebase.auth().onAuthStateChanged(async (user) => {
if (user && !isCancelled) {
await firebase
.firestore()
.collection('users')
.doc(user.uid)
.get()
.then((document) => {
const userData = document.data()
console.log(document.data())
setUser(userData);
setIsSignedIn(true);
setLoading(false);
})
.catch((error) => {
setLoading(false);
alert(error)
});
}else{
console.log('user does not exist')
setIsSignedIn(false);
setLoading(false);
}
});
return () => {
isCancelled = true;
}
}, []);
这是它的图像。也许更清晰
通常,每个useEffect
应该负责一项任务。此外,当前使用isCancelled
的方法实际上并没有像应该的那样清理侦听器。
对于react,您应该尽可能使用实时更新。您还将受益于能够轻松地分离侦听器。
这是一个脚手架,你可以在上面工作。
// Set up a state variable to contain the user's info
// If a user is already logged in and validated, user is immediately
// set to their User object, otherwise show loading icon while we check
const [user, setUser] = useState(() => firebase.auth().currentUser || undefined);
const userLoading = user === undefined;
const isSignedIn = !!user;
// Set up a state variable to contain the user's data
const [userData, setUserData] = useState(undefined);
// Set up a state variable to contain whether this component is loading
const [loading, setLoading] = useState(true);
// effect to track user state and update `user` for any changes
// onAuthStateChanged returns its own cleanup function
useEffect(() => firebase.auth().onAuthStateChanged(setUser), []); // <- don't rerun
// effect to navigate to login
useEffect(() => {
if (user === null) {
// user is signed out
navigation.navigate('login');
}
}, [user]); // <- rerun when user changes
useEffect(async () => {
if (!isSignedIn) return; // you could write this as `userLoading || !isSignedIn`, but it's redundant
return firebase.firestore()
.collection('users')
.doc(user.uid)
.onSnapshot({ // <- onSnapshot() returns its own cleanup function
next(docSnapshot) {
const userData = docSnapshot.data();
setUserData(userData);
},
error(err) {
console.error(err);
alert(err);
}
});
}, [user]); // <- rerun when user changes
作为一个学习项目,可以考虑将其制作成Context
或创建自己的useAuth
函数,在其中可以提取用户的数据、用户对象和加载状态。
试试这个
useEffect(async () => {
let isCancelled = false;
const unsubscribe = await firebase.auth().onAuthStateChanged(async (user) => {
........
});
return () => {
// cleanup
unsubscribe()
isCancelled = true;
}
}, []);
让我知道它是否适合你b