reactjs - 使用 Firebase 在 useEffect 上停止无限循环
问题描述
我第一次用钩子测试firebase,遇到了众所周知的无限循环问题。
我知道还有很多其他问题可能与这个问题很接近,但在这种情况下我仍然无法解决这个问题。
这里是 App.js 上的代码:
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;
这里是 firebase.utils.js 的 createUserProfileDocument 函数:
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;
};
在这种情况下,我将如何检查 onAuthStateChanged 是否实际发生了变化?我得到的印象是 auth.onAuthStateChanged 函数每次都会触发,生成那个无限循环..
这里我检查的资源可能会有所帮助:
先感谢您。
解决方案
该方法onAuthStateChanged
通过为用户的登录状态添加观察者来设置订阅。只需要在组件挂载时订阅一次,组件卸载时调用unsubscribe,防止观察者运行导致内存泄漏。
要回答为什么在您的情况下导致无限循环,您将user
状态作为依赖项,这将导致每次user
更新状态值时重新初始化观察者,并且观察者将返回一个全新的userAuth
对象并setUser
再次被调用,这将更新用户状态,这将重新初始化观察者并一遍又一遍地重复相同的循环。
解决方案,
通过将空数组作为依赖项传递给组件,仅在组件挂载时设置一次订阅useEffect
function App() {
const [user, setUser] = useState(null);
useEffect(() => {
// auth.onAuthStateChanged will return a firebase.Unsubrcibe function
// which you can call to terminate the subscription
const unsubscribe = auth.onAuthStateChanged(async userAuth => {
if (userAuth) {
const userRef = await createUserProfileDocument(userAuth);
userRef.onSnapshot(snapshot => {
setUser({
user: {
id: snapshot.id,
...snapshot.data()
}
})
});
} else {
setUser(null);
}
});
// return a clean up function that will call unsubscribe to -
// terminate the subscription when component unmounts
return () => { unsubscribe() }
}, []); // important set an empty array as dependency
return (
<div></div>
);
}
export default App;
编辑-不要尝试将user
变量记录在同一个useEffect
钩子中,因为它需要一个空的依赖数组,而是使用另一个useEffect
钩子来记录user
传递user
as 依赖项的值。例子
useEffect(() => {
console.log(user)
}, [user])
推荐阅读
- java - 使用 Comparator 时 TreeMap 行为的 Submap()
- android - Android 自定义形状图像裁剪
- c# - 超过 1 个 HttpPost 正在激活
- http - http请求会自动重试吗?
- javascript - 如何将组件作为道具传递给反应中的道具?
- android - Android O - 单行通知 - 类似于“Android 系统 - USB 充电此设备”
- ios - 使用 navCtrl 推送页面时,Ionic 3、iOS、iPhone X 崩溃并重新加载
- php - 比较不同的数组结构
- excel - 在excel中具有双重条件的For/While循环
- ios - 带有阿拉伯标题和图像问题的 iOS UIButton