ReactJS 中 Firebase 身份验证状态更改时设置状态

问题描述 投票:0回答:3

我正在编写一个 ReactJS 应用程序,其中有一个提供程序类 (AuthProvider.js) 处理 Firebase 身份验证。它的几个子级使用 auth 状态。大约一个月以来一切都工作正常,但上周末我们开始遇到问题,可能是因为一些升级,我正在尝试排除故障。基本上,在 AuthProvider 组件中,我有一个

currentUser
状态,当没有人登录时该状态应该为 null,或者当有人登录时包含有关当前用户的一些数据。可能只是 UID。可能是完整的用户对象。可能是一个布尔值。在这一点上我们并不挑剔。基本上,当我尝试教科书方法时

  useEffect(() => {
    const unsubscribe = firebase.auth().onAuthStateChanged(user => {
       setCurrentUser(user);
    });

    // Cleanup subscription on unmount
    return () => unsubscribe();
  }, []);

在 AuthProvider 类(有或没有 useEffect)中,我得到“渲染的钩子比预期少”。我听到一些关于在回调函数中使用 setState 是一个坏主意的陈词滥调,但是在设置

errors
(另一个像
currentUser
一样导出的状态对象)时没有任何问题。

是否有一种安全可靠的方法可以让我从 AuthProvider 的子组件观察 firebase 状态,并且代码重复最少?通常,我有几种情况,向客人展示一个组件,向成员展示另一个组件,因此状态对我来说很重要。

reactjs firebase react-hooks
3个回答
1
投票

试试这个:

useEffect(() => {
    const unsubscribe = firebase.auth().onAuthStateChanged(user => {
    if(user){
        setCurrentUser(user);
         }else{
        setCurrentUser(null);
      }
    });

    // Cleanup subscription on unmount
    return () => unsubscribe();
  }, []);

0
投票

我认为最好的方法是使用 context-api 或 redux 来使用全局状态。因为用户状态在你的项目中是一个非常重要的状态。当您有更多组件时,您必须将一个组件的用户状态传递给另一组件。我认为这不是一个好的做法,你不能每次都这样做。

如果您使用我上面提到的任何状态管理系统,那么您可以从 onAuthStateChanged 获取经过身份验证的用户并将其分派到全局状态。然后您可以在项目中的任何地方使用该状态。

 useEffect(() => {

    auth.onAuthStateChanged(userAuth => {
      dispatch({
        type: actionTypes.SET_USER,
        user: userAuth,
      })
    })
  }, [])

注意:这不是完整的代码,您首先必须在 redux 或 context-api 中创建减速器和其他减速器。然后就可以用这个了。


0
投票

我发现更干净、更实用的另一种方法是在单独的文件“useAuthHook.ts”上使用自定义挂钩,然后在组件上使用它:

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.production.min.js"></script>
import { useEffect, useMemo, useState } from "react"
import { auth } from "../services/firebaseAuth"
import { User } from "firebase/auth"

export const useAuth = () => {

    const [authStateLoading, setauthStateLoading] = useState<boolean>(true);

    const [userAuth, setUserAuth] = useState<User | null | undefined>(undefined);

    const isUserAuthenticated: boolean | undefined = useMemo(() => {
        if (authStateLoading) {
            return undefined;
        }

        return userAuth !== null;
    }, [userAuth]);

    useEffect(() => auth.onAuthStateChanged((userAuth: User | null) => {
        setUserAuth(userAuth);
        if (authStateLoading) {
            setauthStateLoading(false);
        }
    }), [])

    return {
        authStateLoading, userAuth, isUserAuthenticated
    }
}

这是我们如何在组件中使用的示例:

//.....

// Before rendering component, if "Auth State was checked" and "User not authenticated" => redirect to login page
if (!authStateLoading && requiresAuth && !isUserAuthenticated) {
  redirectUnauthorized();
}

// Rendering component

return authStateLoading
    ? <Loader message="Pending..." />
    : <div>MY COMPONENT</div>

希望有帮助!

© www.soinside.com 2019 - 2024. All rights reserved.