首页 > 解决方案 > 尝试获取用户的身份验证状态firebase时反应本机useEffect渲染问题

问题描述

我对 useEffect 有疑问。当我尝试在 之后获取用户的身份验证状态时,onAuthStateChangeduseEffect 中的调用次数非常高。有时它也会给出这个错误:

警告:无法对未安装的组件执行 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;
    }
  }, []);

这是它的形象。也许更清楚

标签: reactjsfirebasereact-nativefirebase-authenticationuse-effect

解决方案


一般来说,每个人都useEffect应该负责一项任务。此外,当前的使用方法isCancelled实际上并没有像他们应该的那样清理听众。

对于反应,您应该尽可能使用实时更新。您还将受益于能够轻松分离侦听器。

这是您可以使用的脚手架。

// 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函数,您可以在其中提取用户数据、用户对象和加载状态。


推荐阅读