登录页面在使用Firebase Auth刷新React主页时显示。

huangapple go评论61阅读模式
英文:

Login page is displayed when I refresh Homepage in React with Firebase Auth

问题

I implemented Firebase authentication in my app by the docs. I have a login screen and a landing screen which is accessed only if you are logged in.

For some reason, when I am logged in and I refresh my landing screen, it redirects me to the login screen and then back to the landing screen.

Here is some code that could help you out:

index.js (imports and other stuff is left out)

root.render(
  <AuthProvider>
    <Router>
      <Toaster />
      <AppRouter />
    </Router>    
  </AuthProvider>    
);

AuthProvider.js

import React, { useEffect, useState } from "react";
import { onAuthStateChanged } from "firebase/auth";
import { FirebaseAuth } from "./firebase/config";

export const AuthContext = React.createContext();

export const AuthProvider = ({ children }) => {
  const [currentUser, setCurrentUser] = useState(null);

  useEffect(() => {
    onAuthStateChanged(FirebaseAuth, user => {
      if (user) {
        setCurrentUser(user)
      } else {
        setCurrentUser(null)
      }
    })
  }, []);

  return (
    <AuthContext.Provider value={{ currentUser }}>
      {children}
    </AuthContext.Provider>
  );
};

And here is the AppRouter.js

import { useContext } from "react";
import Landing from "./screens/Landing";
import {
  Navigate,
  BrowserRouter,
  Routes,
  Route
} from "react-router-dom";
import Login from "./screens/auth/Login";
import { AuthContext } from './AuthProvider';

const AppRouter = () => {
  const { currentUser } = useContext(AuthContext);

  return (
    <Routes>
      <Route
        path="/"
        element={!!currentUser ? <Landing /> : <Navigate to="/login" />}
        exact
      />
      <Route
        path="/login"
        element={!currentUser ? <Login /> : <Navigate to="/" />}
        exact
      />
    </Routes>
  )
}

export default AppRouter;
英文:

I implemented Firebase authentication in my app by the docs. I have a login screen and a landing screen which is accessed only if you are logged in.

For some reason, when I am logged in and I refresh my landing screen, it redirects me to login screen and then back to the landing screen. I'm having a hard time figuring out why.

Here is some code that could help you out:

index.js (imports and other stuff is left out)

root.render(
  &lt;AuthProvider&gt;
    &lt;Router&gt;
      &lt;Toaster /&gt;
      &lt;AppRouter /&gt;
    &lt;/Router&gt;    
  &lt;/AuthProvider&gt;    
);

AuthProvider.js

import React, { useEffect, useState } from &quot;react&quot;;
import { onAuthStateChanged } from &quot;firebase/auth&quot;;
import { FirebaseAuth } from &quot;./firebase/config&quot;;

export const AuthContext = React.createContext();

export const AuthProvider = ({ children }) =&gt; {
  const [currentUser, setCurrentUser] = useState(null);

  useEffect(() =&gt; {
    onAuthStateChanged(FirebaseAuth, user =&gt; {
      if (user) {
        setCurrentUser(user)
      } else {
        setCurrentUser(null)
      }
    })
  }, []);

  return (
    &lt;AuthContext.Provider value={{ currentUser }}&gt;
      {children}
    &lt;/AuthContext.Provider&gt;
  );
};

And here is the AppRouter.js

import { useContext } from &quot;react&quot;;
import Landing from &quot;./screens/Landing&quot;
import {
  Navigate,
  BrowserRouter,
  Routes,
  Route
} from &quot;react-router-dom&quot;;
import Login from &quot;./screens/auth/Login&quot;;
import { AuthContext } from &#39;./AuthProvider&#39;;

const AppRouter = () =&gt; {
  const { currentUser } = useContext(AuthContext);

  return (
    &lt;Routes&gt;
      &lt;Route
        path=&quot;/&quot;
        element={!!currentUser ? &lt;Landing /&gt; : &lt;Navigate to=&quot;/login&quot; /&gt;}
        exact
      /&gt;
      &lt;Route
        path=&quot;/login&quot;
        element={!currentUser ? &lt;Login /&gt; : &lt;Navigate to=&quot;/&quot; /&gt;}
        exact
      /&gt;
    &lt;/Routes&gt;
  )
}

export default AppRouter;

答案1

得分: 2

初始的 currentUser 状态与已确认的“未认证”用户状态匹配,例如 null。当应用程序加载时,将使用此初始的假值来渲染路由。

请使用一个既不是“已认证”也不是“未认证”的初始 currentUser 状态值,并对此进行明确检查,以便在应用程序早期有条件地返回,这样应用程序既不会渲染受保护的内容,也不会重定向。

export const AuthProvider = ({ children }) => {
  const [currentUser, setCurrentUser] = useState(); // <-- 最初是未定义的

  useEffect(() => {
    onAuthStateChanged(FirebaseAuth, user => {
      if (user) {
        setCurrentUser(user);
      } else {
        setCurrentUser(null);
      }
    });
  }, []);

  return (
    <AuthContext.Provider value={{ currentUser }}>
      {children}
    </AuthContext.Provider>
  );
};
const AppRouter = () => {
  const { currentUser } = useContext(AuthContext);

  if (currentUser === undefined) {
    return null; // <-- 或者加载指示器/旋转等
  }

  return (
    <Routes>
      <Route
        path="/"
        element={!!currentUser ? <Landing /> : <Navigate to="/login" />}
      />
      <Route
        path="/login"
        element={!currentUser ? <Login /> : <Navigate to="/" />}
      />
    </Routes>
  );
}

要更传统地实现路由保护的方法,请查看我的答案这里

英文:

The initial currentUser state matches the confirmed "unauthenticated" user state, e.g. null. When the app mounts, this initial falsey value will be used when rendering the routes.

Use an initial currentUser state value that is neither "authenticated" nor "unauthenticated" and do an explicit check for this and conditionally return early so the app neither renders the protected content nor the redirect.

export const AuthProvider = ({ children }) =&gt; {
  const [currentUser, setCurrentUser] = useState(); // &lt;-- initially undefined

  useEffect(() =&gt; {
    onAuthStateChanged(FirebaseAuth, user =&gt; {
      if (user) {
        setCurrentUser(user);
      } else {
        setCurrentUser(null);
      }
    });
  }, []);

  return (
    &lt;AuthContext.Provider value={{ currentUser }}&gt;
      {children}
    &lt;/AuthContext.Provider&gt;
  );
};
const AppRouter = () =&gt; {
  const { currentUser } = useContext(AuthContext);

  if (currentUser === undefined) {
    return null; // &lt;-- or loading indicator/spinner/etc
  }

  return (
    &lt;Routes&gt;
      &lt;Route
        path=&quot;/&quot;
        element={!!currentUser ? &lt;Landing /&gt; : &lt;Navigate to=&quot;/login&quot; /&gt;}
      /&gt;
      &lt;Route
        path=&quot;/login&quot;
        element={!currentUser ? &lt;Login /&gt; : &lt;Navigate to=&quot;/&quot; /&gt;}
      /&gt;
    &lt;/Routes&gt;
  );
}

For a more conventional method of implementing route protection see my answer here.

huangapple
  • 本文由 发表于 2023年6月1日 05:59:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/76377550.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定