如何在私有路由组件中放置加载标志?

How can I put a loading sign inside the Private route component?

这是 PrivateRoute 组件:

import React from "react";
import { Navigate, Outlet, useLocation } from "react-router-dom";

import { useAuth } from "../../Firebase/utils";

const PrivateRoute = ({ children }) => {
  let currentUser = useAuth();

  if (!currentUser) {
    return <Navigate to="/login" />;
  }

  return children;
};

export default PrivateRoute;

App.js

 <Route
                path="/Page"
                element={
                  <PrivateRoute>
                      <Page />
                  </PrivateRoute>
                }
              />

有没有办法在 PrivateRoute 中加载?

这是我的 useAuth:

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 };
}

这是App.js

function App() {
  const { currentUser, isLoading } = useAuth();
  const user = auth.currentUser;
  const navigate = useNavigate();

  console.log(currentUser?.email);

  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("/Home");
        // ...
      } else {
        // User is signed out
        // ...
        navigate("/login");
      }
    });

    return () => {
      unsub();
    };
  }, []);

  return (
    <div>
      <div>
        <Routes>
          {!isLoading ? (
            <>
              <Route
                path="/login"
                element={
                    <SignInPage />
                }
              />
              <Route
                path="/Home"
                element={
                  <PrivateRoute>
                    <Homepage />
                  </PrivateRoute>
                }
              />
            </>
          ) : (
            <>
              <Route
                path="/login"
                element={
                    <SignInPage />
                }
              />
            </>
          )}

          <Route
            path="/reset-password"
            element={
                <ResetPasswordPage />
            }
          />
        </Routes>
      </div>
    </div>
  );
}

export default App;

useAuth 挂钩 returns 具有 isLoading 初始状态的对象:

export function useAuth() {
  const [isLoading, setIsLoading] = useState(true);
  const [currentUser, setCurrentUser] = useState();

  useEffect(() => {
    const unsub = onAuthStateChanged(auth, (user) => {
      setCurrentUser(user);
      setIsLoading(false); // finished checking
    });
    return unsub;
  }, []);

  return { currentUser, isLoading };
}

PrivateRoute 组件中访问此 isLoading 状态以有条件地呈现 null 或一些加载指示器,除 children 属性或重定向到登录路由之外的任何内容。

const PrivateRoute = ({ children }) => {
  const { currentUser, isLoading } = useAuth();

  if (isLoading) {
    return null; // or loading spinner, etc...
  }

  if (!currentUser) {
    return <Navigate to="/login" replace />;
  }

  return children;
};

您也可以只渲染所有路线,其中一些在必要时使用 PrivateRoute 包装器。

function App() {
  const { currentUser } = useAuth();
  const navigate = useNavigate();

  console.log(currentUser?.email);

  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("/Home");
        // ...
      } else {
        // User is signed out
        // ...
        navigate("/login");
      }
    });

    return () => {
      unsub();
    };
  }, []);

  return (
    <div>
      <div>
        <Routes>
          <Route path="/login" element={<SignInPage />} />
          <Route
            path="/Home"
            element={
              <PrivateRoute>
                <Homepage />
              </PrivateRoute>
            }
          />
          <Route path="/reset-password" element={<ResetPasswordPage />} />
        </Routes>
      </div>
    </div>
  );
}