0

我正在将一个项目从 Angular 重写为 ReactJS,所以我对它应该如何工作有一些预先存在的想法: 我正在尝试使用当前的 firebase.auth() 从 Firestore 获取我的用户文档并将其保存为静态对象(以避免对 Firebase 的冗余调用)。

在 Angular 中,您可以使用服务文件(单例)来监听 firebase.auth() 状态,使用 currentUser.uid 调用 firestore,并存储 doc 对象以供任何组件抓取和使用。

在 React 中,似乎正确的方法是通过全局状态,或者我决定采用的方法,一个自定义钩子。


// Custom Hook useCurrentUser
import { doc, onSnapshot } from 'firebase/firestore';
import { useEffect, useState } from 'react';
import firebase from '../Firebase';

const db = firebase.firestore();

export default function useCurrentUser() {
    const [authUser, setAuthUser] = useState(null);
    const [user, setUser] = useState(null);

    // Listen to Auth User
    useEffect(() => {
        const unsubscribe = firebase.auth().onAuthStateChanged(u => {
            console.log('authStateChanged', u);
            setAuthUser(u);
        });

        return unsubscribe();
    });

    // Get User doc from Firestore
    useEffect(() => {
        let subscription;
        console.log('authUser', authUser);
        if (authUser) {
            const docRef = doc(db, 'users', authUser.uid);
            subscription = onSnapshot(docRef, snapshot => {
                const data = snapshot.data();
                console.log('CurrentUserHook', data);
                setUser(data);
            });
        } else {
            setUser(null);
        }

        return () => {
            if (subscription) subscription();
        };
    }, [authUser]);

    return user;
}

// Firebase.js
import firebase from 'firebase/compat/app';

const firebaseConfig = { /* config stuff */ };
firebase.initializeApp(firebaseConfig);

export default firebase;

// Component implementing useCurrentUser
function UserMenu() {
  const user = useCurrentUser();

  return (
    <div>
      { /* This is a menu that closes on click */ }
      {user ?
        <LoggedInMenu user={user} /> :
        <LoggedOutMenu />}
    </div>
  );
}

问题:单击该 UserMenu 中的按钮(如 Login 或 Logout)后,菜单关闭(不再呈现),并且在 useCurrentUser() 中实际接收新 AuthState 的最终操作不会发生。因此,用户单击 logout(),菜单关闭,并且用户保持登录状态,直到再次单击该菜单以调用渲染并让这些 useEffects() 再次运行。

这感觉像是一种非常干净、简单的方法来处理身份验证和获取我的自定义用户文档,但我缺少最后一点让它完全工作。我需要再进行一个渲染循环,但我不知道该怎么做。或者,在 React 中可能有更好的方法来实现这个目标。

4

0 回答 0