如何使用 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 - 无条件渲染所有路由,将 HomeProfile 路由包装在 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>
  );
}