如何使用 React-Router 将页面限制为访客用户?
How can I restrict pages to guest users using React-Router?
我正在使用 Firebase v9 和 react-router v6。我没有使用过 v6,所以这很令人困惑。我怎样才能使来宾用户只能访问登录页面。只有已登录的用户才能访问主页和其他页面。
每次我重新加载任何页面时,它都会在控制台中显示此内容,但它仍会将用户引导至正确的页面:
No routes matched location "/location of the page"
如何为个人资料页面使用私人路线?
//custom hook
export function useAuth() {
const [currentUser, setCurrentUser] = useState();
useEffect(() => {
const unsub = onAuthStateChanged(auth, (user) => setCurrentUser(user));
return unsub;
}, []);
return currentUser;
}
App.js
import { auth, useAuth } from "./Firebase/utils";
import { onAuthStateChanged } from "firebase/auth";
function App() {
const currentUser = useAuth();
const user = auth.currentUser;
const navigate = useNavigate();
console.log(currentUser?.email);
useEffect(() => {
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("/Home");
// ...
} else {
// User is signed out
// ...
navigate("/");
}
});
}, []);
return (
<div>
<div>
<Routes>
{currentUser ? (
<>
//If i do it this way and I'll go the profile page and reload it, it will always go to back to the Homepage.
<Route path="/Home" element={<Home />} />
<Route path="/Profile" element={<ProfilePage />} />
</>
) : (
<>
<Route
path="/"
element={
<LogInPage />
}
/>
</>
)}
</Routes>
</div>
</div>
);
}
export default App;
这是 console.log(user)
显示的内容:
Package.json 文件:
问题
主要问题是 currentUser
值最初是错误的
const [currentUser, setCurrentUser] = useState();
并且您正在 App
中对未确认的身份验证状态做出导航决定
<Routes>
{currentUser ? (
<>
// If i do it this way and I'll go the profile page and reload it,
// it will always go to back to the Homepage.
<Route path="/Home" element={<Home />} />
<Route path="/Profile" element={<ProfilePage />} />
</>
) : (
<>
<Route
path="/"
element={<LogInPage />}
/>
</>
)}
</Routes>
刷新页面时,currentUser
状态被重置,未定义,即错误,仅呈现 "/"
路径。
解决方案
在 react-router-dom
中,将路由保护抽象为专门的“受保护路由”组件是一种常见的做法。您还需要有条件地处理不确定状态,直到您的 Firebase 身份验证检查有机会确认身份验证状态并更新 currentUser
状态。
示例:
export function useAuth() {
const [currentUser, setCurrentUser] = useState({}); // <-- provide object to destructure from
useEffect(() => {
const unsub = onAuthStateChanged(auth, (user) => setCurrentUser(user));
return unsub;
}, []);
return currentUser;
}
AuthWrapper - 使用 useAuth
挂钩检查用户的身份验证状态。如果 currentUser
未定义,它有条件地 returns 提前 null
或其他一些加载指示器。一旦 currentUser
状态为 populated/defined,该组件有条件地为您要保护的 nested/wrapped Route
组件呈现 Outlet
,或者 Navigate
组件重定向到您的授权路线。
import { Navigate, Outlet, useLocation } from 'react-router-dom';
const AuthWrapper = () => {
const location = useLocation();
const { currentUser } = useAuth();
if (currentUser === undefined) return null; // <-- or loading spinner, etc...
return currentUser
? <Outlet />
: <Navigate to="/" replace state={{ from: location }} />;
};
App - 无条件渲染所有路由,将 Home
和 Profile
路由包装在 AuthWrapper
布局路由中。
function App() {
return (
<div>
<div>
<Routes>
<Route element={<AuthWrapper />}>
<Route path="/Home" element={<Home />} />
<Route path="/Profile" element={<ProfilePage />} />
</Route>
<Route path="/" element={<LogInPage />} />
</Routes>
</div>
</div>
);
}
我正在使用 Firebase v9 和 react-router v6。我没有使用过 v6,所以这很令人困惑。我怎样才能使来宾用户只能访问登录页面。只有已登录的用户才能访问主页和其他页面。
每次我重新加载任何页面时,它都会在控制台中显示此内容,但它仍会将用户引导至正确的页面:
No routes matched location "/location of the page"
如何为个人资料页面使用私人路线?
//custom hook
export function useAuth() {
const [currentUser, setCurrentUser] = useState();
useEffect(() => {
const unsub = onAuthStateChanged(auth, (user) => setCurrentUser(user));
return unsub;
}, []);
return currentUser;
}
App.js
import { auth, useAuth } from "./Firebase/utils";
import { onAuthStateChanged } from "firebase/auth";
function App() {
const currentUser = useAuth();
const user = auth.currentUser;
const navigate = useNavigate();
console.log(currentUser?.email);
useEffect(() => {
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("/Home");
// ...
} else {
// User is signed out
// ...
navigate("/");
}
});
}, []);
return (
<div>
<div>
<Routes>
{currentUser ? (
<>
//If i do it this way and I'll go the profile page and reload it, it will always go to back to the Homepage.
<Route path="/Home" element={<Home />} />
<Route path="/Profile" element={<ProfilePage />} />
</>
) : (
<>
<Route
path="/"
element={
<LogInPage />
}
/>
</>
)}
</Routes>
</div>
</div>
);
}
export default App;
这是 console.log(user)
显示的内容:
Package.json 文件:
问题
主要问题是 currentUser
值最初是错误的
const [currentUser, setCurrentUser] = useState();
并且您正在 App
<Routes>
{currentUser ? (
<>
// If i do it this way and I'll go the profile page and reload it,
// it will always go to back to the Homepage.
<Route path="/Home" element={<Home />} />
<Route path="/Profile" element={<ProfilePage />} />
</>
) : (
<>
<Route
path="/"
element={<LogInPage />}
/>
</>
)}
</Routes>
刷新页面时,currentUser
状态被重置,未定义,即错误,仅呈现 "/"
路径。
解决方案
在 react-router-dom
中,将路由保护抽象为专门的“受保护路由”组件是一种常见的做法。您还需要有条件地处理不确定状态,直到您的 Firebase 身份验证检查有机会确认身份验证状态并更新 currentUser
状态。
示例:
export function useAuth() {
const [currentUser, setCurrentUser] = useState({}); // <-- provide object to destructure from
useEffect(() => {
const unsub = onAuthStateChanged(auth, (user) => setCurrentUser(user));
return unsub;
}, []);
return currentUser;
}
AuthWrapper - 使用 useAuth
挂钩检查用户的身份验证状态。如果 currentUser
未定义,它有条件地 returns 提前 null
或其他一些加载指示器。一旦 currentUser
状态为 populated/defined,该组件有条件地为您要保护的 nested/wrapped Route
组件呈现 Outlet
,或者 Navigate
组件重定向到您的授权路线。
import { Navigate, Outlet, useLocation } from 'react-router-dom';
const AuthWrapper = () => {
const location = useLocation();
const { currentUser } = useAuth();
if (currentUser === undefined) return null; // <-- or loading spinner, etc...
return currentUser
? <Outlet />
: <Navigate to="/" replace state={{ from: location }} />;
};
App - 无条件渲染所有路由,将 Home
和 Profile
路由包装在 AuthWrapper
布局路由中。
function App() {
return (
<div>
<div>
<Routes>
<Route element={<AuthWrapper />}>
<Route path="/Home" element={<Home />} />
<Route path="/Profile" element={<ProfilePage />} />
</Route>
<Route path="/" element={<LogInPage />} />
</Routes>
</div>
</div>
);
}