Reactjs 使用Firebase停止useEffect上的无限循环

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,

我第一次用钩子测试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;
在这种情况下,如何检查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;
};