英文:
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(
<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;
答案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 }) => {
const [currentUser, setCurrentUser] = useState(); // <-- initially undefined
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; // <-- or loading indicator/spinner/etc
}
return (
<Routes>
<Route
path="/"
element={!!currentUser ? <Landing /> : <Navigate to="/login" />}
/>
<Route
path="/login"
element={!currentUser ? <Login /> : <Navigate to="/" />}
/>
</Routes>
);
}
For a more conventional method of implementing route protection see my answer here.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论