如何防止当前页面在刷新时重定向到另一个页面?
How to prevent the current page from redirecting to another page when refreshing?
每次我重新加载个人资料页面时,它都会自行重定向到主页。我该如何解决这个问题?
用户成功登录后,他或她将被定向到主页。在主页上,有一个配置文件页面。我可以成功加载个人资料页面,但是,一旦我重新加载它,用户将再次被重定向到主页。
//custom hook
export function useAuth() {
const [currentUser, setCurrentUser] = useState();
useEffect(() => {
const unsub = onAuthStateChanged(auth, (user) => setCurrentUser(user));
return unsub;
}, []);
return currentUser;
}
App.js
function App() {
const currentUser = useAuth();
const user = auth.currentUser;
const navigate = useNavigate();
useEffect(() => {
const unsub = onAuthStateChanged(auth, (user) => {
if (user) {
// User is signed in, see docs for a list of available properties
// https://firebase.google.com/docs/reference/js/firebase.User
const uid = user.uid;
console.log(uid);
navigate("/Homepage");
// ...
} else {
// User is signed out
// ...
navigate("/");
}
});
return unsub;
}, []);
return (
<div>
<div>
<Routes>
{currentUser ? (
<>
<Route
path="/"
element={
<MainLayout>
<LoginPage />
</MainLayout>
}
/>
<Route path="/Homepage" element={<Home />} />
<Route path="/Profile" element={<ProfilePage />} />
</>
) : (
<>
<Route
path="/"
element={
<MainLayout>
<LoginPage />
</MainLayout>
}
/>
</>
)}
</Routes>
</div>
</div>
);
}
export default App;
如果我 console.log(currentUser)
这就是它显示的内容:
也在:https://www.reddit.com/r/reactjs/comments/smfsro/how_to_prevent_the_page_from_redirecting_to/
受保护的路线:
{currentUser ? (
<>
<Route
path="/"
element={
<MainLayout>
<LoginPage />
</MainLayout>
}
/>
<Route path="/Homepage" element={<Home />} />
<Route
path="/Profile"
element={
<PrivateRoute>
<ProfilePage />
</PrivateRoute>
}
/>
</>
) : (
<>
<Route
path="/"
element={
<MainLayout>
<LoginPage />
</MainLayout>
}
/>
</>
)}
私有路由
import React from "react";
import { Navigate, Outlet, useLocation } from "react-router-dom";
import { useAuth } from "../../Firebase/utils";
const PrivateRoute = () => {
const currentUser = useAuth();
// // const !currentUser = null; // determine if authorized, from context or however you're doing it
// // If authorized, return an outlet that will render child elements
// // If not, return element that will navigate to login page
// return currentUser ? <Outlet /> : <Navigate to="/" />;
let location = useLocation();
if (!currentUser) {
console.log(currentUser);
return <Navigate to="/" state={{ from: location }} replace />;
}
};
export default PrivateRoute;
我认为问题是 currentUser
没有默认值,所以当您第一次加载页面时它总是 undefined
。您应该添加加载状态以确保在使用 currentUser
执行任何逻辑之前检查用户的状态。
注意:我没有运行下面的任何代码,所以可能会有一些错误,但这只是一个大概的参考。
export function useAuth() {
const [isLoading, setIsLoading] = useState(true); // checking the user's status
const [currentUser, setCurrentUser] = useState();
useEffect(() => {
const unsub = onAuthStateChanged(auth, (user) => {
setCurrentUser(user)
setIsLoading(false) // finished checking
});
return unsub;
}, []);
return {currentUser, isLoading};
}
因此,当您检查用户是否已登录时:
if(!isLoading && currentUser){
// is finished loading and user is logged in
}
我还建议您将 currentUser
存储在上下文中而不是使用自定义挂钩,因为自定义挂钩不允许您在组件之间共享状态,并且每次使用它时都会挂载它。
相反,您的挂钩可用于从上下文中获取值。
像这样:
// store currentUser inside context
const AuthContext = createContext();
export const AuthProvider = ({children}) => {
const [isLoading, setIsLoading] = useState(true);
const [currentUser, setCurrentUser] = useState();
useEffect(() => {
const unsub = onAuthStateChanged(auth, (user) => {
setCurrentUser(user)
setIsLoading(false)
});
return unsub;
}, []);
return (
<AuthContext.Provider value={{currentUser, isLoading}}>
{children}
</AuthContext.Provider>
)
}
// read context value with custom hook
export useAuth = () => useContext(AuthContext)
当您使用 useAuth
时它仍然是相同的,只是它从上下文中获取状态。
const {currentUser, isLoading} = useAuth()
---编辑问题---
上下文用于在整个应用程序中共享数据,当您需要在多个地方使用相同的数据时它非常有用。您可以存储数据并通过 提供者 向下传递,并通过 消费者 访问它。我不会详细介绍,但您可以在此处阅读有关 Context API 的更多信息:https://reactjs.org/docs/context.html#gatsby-focus-wrapper
关于AuthProvider的使用方法,一般可以这样包装在App.js
// App.js
<AuthProvider>
<div>
<Routes>{/* ... */}</Routes>
</div>
</AuthProvider>
但在这种情况下,由于您已经在 App.js 中使用 currentUser
,因此您必须将 AuthProvider 更新为 HOC,并将其包装在您的组件周围
// AuthContext
export const withAuthProvider = WrappedComponent => ({children}) => {
// ... the rest is the same
}
// App.js
export default withAuthProvider(App);
这是因为上下文值只能在提供者所环绕的范围内访问。如果没有 HOC,您的提供者将包裹在您的路由中,这意味着该值无法在 App.js 本身中访问,但可以在 MainLayout、LoginPage 等中访问。然而,使用 HOC,因为您已经包裹了整个 App.js,它可以访问AuthContext中的值。
每次我重新加载个人资料页面时,它都会自行重定向到主页。我该如何解决这个问题?
用户成功登录后,他或她将被定向到主页。在主页上,有一个配置文件页面。我可以成功加载个人资料页面,但是,一旦我重新加载它,用户将再次被重定向到主页。
//custom hook
export function useAuth() {
const [currentUser, setCurrentUser] = useState();
useEffect(() => {
const unsub = onAuthStateChanged(auth, (user) => setCurrentUser(user));
return unsub;
}, []);
return currentUser;
}
App.js
function App() {
const currentUser = useAuth();
const user = auth.currentUser;
const navigate = useNavigate();
useEffect(() => {
const unsub = onAuthStateChanged(auth, (user) => {
if (user) {
// User is signed in, see docs for a list of available properties
// https://firebase.google.com/docs/reference/js/firebase.User
const uid = user.uid;
console.log(uid);
navigate("/Homepage");
// ...
} else {
// User is signed out
// ...
navigate("/");
}
});
return unsub;
}, []);
return (
<div>
<div>
<Routes>
{currentUser ? (
<>
<Route
path="/"
element={
<MainLayout>
<LoginPage />
</MainLayout>
}
/>
<Route path="/Homepage" element={<Home />} />
<Route path="/Profile" element={<ProfilePage />} />
</>
) : (
<>
<Route
path="/"
element={
<MainLayout>
<LoginPage />
</MainLayout>
}
/>
</>
)}
</Routes>
</div>
</div>
);
}
export default App;
如果我 console.log(currentUser)
这就是它显示的内容:
也在:https://www.reddit.com/r/reactjs/comments/smfsro/how_to_prevent_the_page_from_redirecting_to/
受保护的路线:
{currentUser ? (
<>
<Route
path="/"
element={
<MainLayout>
<LoginPage />
</MainLayout>
}
/>
<Route path="/Homepage" element={<Home />} />
<Route
path="/Profile"
element={
<PrivateRoute>
<ProfilePage />
</PrivateRoute>
}
/>
</>
) : (
<>
<Route
path="/"
element={
<MainLayout>
<LoginPage />
</MainLayout>
}
/>
</>
)}
私有路由
import React from "react";
import { Navigate, Outlet, useLocation } from "react-router-dom";
import { useAuth } from "../../Firebase/utils";
const PrivateRoute = () => {
const currentUser = useAuth();
// // const !currentUser = null; // determine if authorized, from context or however you're doing it
// // If authorized, return an outlet that will render child elements
// // If not, return element that will navigate to login page
// return currentUser ? <Outlet /> : <Navigate to="/" />;
let location = useLocation();
if (!currentUser) {
console.log(currentUser);
return <Navigate to="/" state={{ from: location }} replace />;
}
};
export default PrivateRoute;
我认为问题是 currentUser
没有默认值,所以当您第一次加载页面时它总是 undefined
。您应该添加加载状态以确保在使用 currentUser
执行任何逻辑之前检查用户的状态。
注意:我没有运行下面的任何代码,所以可能会有一些错误,但这只是一个大概的参考。
export function useAuth() {
const [isLoading, setIsLoading] = useState(true); // checking the user's status
const [currentUser, setCurrentUser] = useState();
useEffect(() => {
const unsub = onAuthStateChanged(auth, (user) => {
setCurrentUser(user)
setIsLoading(false) // finished checking
});
return unsub;
}, []);
return {currentUser, isLoading};
}
因此,当您检查用户是否已登录时:
if(!isLoading && currentUser){
// is finished loading and user is logged in
}
我还建议您将 currentUser
存储在上下文中而不是使用自定义挂钩,因为自定义挂钩不允许您在组件之间共享状态,并且每次使用它时都会挂载它。
相反,您的挂钩可用于从上下文中获取值。
像这样:
// store currentUser inside context
const AuthContext = createContext();
export const AuthProvider = ({children}) => {
const [isLoading, setIsLoading] = useState(true);
const [currentUser, setCurrentUser] = useState();
useEffect(() => {
const unsub = onAuthStateChanged(auth, (user) => {
setCurrentUser(user)
setIsLoading(false)
});
return unsub;
}, []);
return (
<AuthContext.Provider value={{currentUser, isLoading}}>
{children}
</AuthContext.Provider>
)
}
// read context value with custom hook
export useAuth = () => useContext(AuthContext)
当您使用 useAuth
时它仍然是相同的,只是它从上下文中获取状态。
const {currentUser, isLoading} = useAuth()
---编辑问题---
上下文用于在整个应用程序中共享数据,当您需要在多个地方使用相同的数据时它非常有用。您可以存储数据并通过 提供者 向下传递,并通过 消费者 访问它。我不会详细介绍,但您可以在此处阅读有关 Context API 的更多信息:https://reactjs.org/docs/context.html#gatsby-focus-wrapper
关于AuthProvider的使用方法,一般可以这样包装在App.js
// App.js
<AuthProvider>
<div>
<Routes>{/* ... */}</Routes>
</div>
</AuthProvider>
但在这种情况下,由于您已经在 App.js 中使用 currentUser
,因此您必须将 AuthProvider 更新为 HOC,并将其包装在您的组件周围
// AuthContext
export const withAuthProvider = WrappedComponent => ({children}) => {
// ... the rest is the same
}
// App.js
export default withAuthProvider(App);
这是因为上下文值只能在提供者所环绕的范围内访问。如果没有 HOC,您的提供者将包裹在您的路由中,这意味着该值无法在 App.js 本身中访问,但可以在 MainLayout、LoginPage 等中访问。然而,使用 HOC,因为您已经包裹了整个 App.js,它可以访问AuthContext中的值。