Reactjs 使用Firebase停止useEffect上的无限循环
我第一次用钩子测试firebase时遇到了众所周知的无限循环问题 我知道还有很多其他问题可能与这个问题很接近,但我仍然无法在这种情况下回避这个问题 下面是App.js上的代码:Reactjs 使用Firebase停止useEffect上的无限循环,reactjs,firebase,react-hooks,Reactjs,Firebase,React Hooks,我第一次用钩子测试firebase时遇到了众所周知的无限循环问题 我知道还有很多其他问题可能与这个问题很接近,但我仍然无法在这种情况下回避这个问题 下面是App.js上的代码: import React, { useState, useEffect } from 'react'; import { auth, createUserProfileDocument } from './firebase/firebase.utils'; function App() { const [user,
import React, { useState, useEffect } from 'react';
import { auth, createUserProfileDocument } from './firebase/firebase.utils';
function App() {
const [user, setUser] = useState(null);
useEffect(() => {
auth.onAuthStateChanged(async userAuth => {
if (userAuth) {
const userRef = await createUserProfileDocument(userAuth);
userRef.onSnapshot(snapshot => {
setUser({
user: {
id: snapshot.id,
...snapshot.data()
}
})
});
console.log(user);
} else {
setUser(null);
}
});
}, [user]);
return (
<div></div>
);
}
export default App;
在这种情况下,如何检查onAuthStateChanged是否已实际更改?我得到的印象是auth.onAuthStateChanged函数每次都会触发,生成无限循环
下面是我检查过的可能有用的资源:
提前感谢。AuthStateChanged方法通过添加用户登录状态的观察者来设置订阅。您只需要在组件挂载时订阅一次,在组件卸载时调用unsubscribe,以防止观察者运行并导致内存泄漏 要回答为什么它会在您的案例中导致无限循环,将
user
状态作为依赖项,这将导致每次更新状态值user
时重新初始化观察者,观察者将返回一个全新的userAuth
对象,并再次调用setUser
,这将更新将重新初始化观察者的用户状态,并一遍又一遍地重复相同的循环
解决方案,
通过将空数组作为依赖项传递给useffect
函数应用程序(){
const[user,setUser]=useState(null);
useffect(()=>{
//auth.onAuthStateChanged将返回firebase.unbrcibe函数
//您可以调用它来终止订阅
const unsubscribe=auth.onAuthStateChanged(异步userAuth=>{
if(userAuth){
const userRef=await createUserProfileDocument(userAuth);
userRef.onSnapshot(快照=>{
设置用户({
用户:{
id:snapshot.id,
…snapshot.data()
}
})
});
}否则{
setUser(空);
}
});
//返回一个清除函数,该函数将调用unsubscribe to-
//组件卸载时终止订阅
return()=>{unsubscribe()}
},[]);//重要信息:将空数组设置为依赖项
返回(
);
}
导出默认应用程序;
编辑-不要尝试将user
变量记录在同一useffect
钩子中,因为它需要一个空的依赖项数组,而是使用另一个useffect
钩子将user
的值作为依赖项传递。范例
useffect(()=>{
console.log(用户)
},[用户])
Legend,这很有效。但是依赖项的空数组呢?这不是一个坏模式吗?因为我使用的是eslint,所以在ExtreatveDeps上得到以下警告:React Hook useEffect缺少依赖项:“user”。要么包含它,要么删除依赖项数组react hooks/depst。在本例中,这不是反模式。因为auth.onAuthStateChanged
的工作原理useffect
必须这样设置,除非您希望将组件重构为类并使用componentDidMount
和componentWillUnmount
生命周期方法,否则没有其他方法。等等,我不明白为什么您需要在相同的useffect
中使用user
变量,您还有console.log(user)吗
在相同的useffect
中。如果是,这就是eslint
抱怨的原因。将console.log(user)
移动到一个新的useffect
。如果要在user
状态更改时记录user
变量,则必须使用另一个useffect
钩子,因为包含auth订阅的useffect
需要一个空的依赖项数组。请参阅更新答案中的编辑部分。啊,是的,这是一个很好的观点。我通过评论警告(//eslint disable line react hooks/deps)找到了一个解决方案,但是您让用户使用不同的useEffect的方式肯定会更好!
export const createUserProfileDocument = async (userAuth, additionalData) => {
if (!userAuth) return;
const userRef = firestore.doc(`users/${userAuth.uid}`);
const snapshot = await userRef.get();
if (!snapshot.exists) {
const { displayName, email } = userAuth;
const createdAt = new Date();
try {
await userRef.set({
displayName,
email,
createdAt,
...additionalData
})
} catch (err) {
console.log('Error creating user', err.message);
}
}
return userRef;
};