I am using React.js and react-router-dom
version 6. I have set up a private Outlet
and made redirecting functionality works.
The problem is if the user is not authenticated and tries to go to the homepage, React shows the homepage but immediately sends the user to the login page. Everything happens in a second. I don't want to show the homepage.
// private Outlet
import axios from "axios";
import { useEffect, useState } from "react";
import { Navigate, Outlet } from "react-router-dom";
export default function PrivateOutlet() {
const [user, setUser] = useState(true);
const [isLoading, setIsLoading] = useState(true);
const getUser = async () => {
try {
const { data } = await axios.get(
`${process.env.REACT_APP_API_URL}auth/login/success`,
{
withCredentials: true,
}
);
console.log(data.isLoggedIn);
setUser(data);
} catch (error) {
setUser(false);
}
};
useEffect(() => {
getUser();
setIsLoading(false);
}, []);
if (isLoading) return <h1>loading</h1>;
return user ? <Outlet /> : <Navigate to="/login" />;
}
// APP.js
import "./App.css";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Home from "./pages/Home";
import Login from "./pages/Login";
import PrivateOutlet from "./components/PrivateOutlet";
function App() {
return (
<BrowserRouter>
<div>
<Routes>
<Route path="/login" element={<Login />} />
<Route element={<PrivateOutlet />}>
<Route path="/" element={<Home />} />
</Route>
</Routes>
</div>
</BrowserRouter>
);
}
export default App;
In your useEffect
, you are calling setIsLoading(false)
just after getUser()
, so the loading state is changed before the API call completes. You could move setIsLoading(false)
inside getUser
in a finally
block, like so:
import axios from "axios";
import { useEffect, useState } from "react";
import { Navigate, Outlet } from "react-router-dom";
export default function PrivateOutlet() {
// set the user to null at first
const [user, setUser] = useState(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
const getUser = async () => {
try {
const { data } = await axios.get(`${process.env.REACT_APP_API_URL}auth/login/success`, {
withCredentials: true,
});
console.log(data.isLoggedIn);
setUser(data);
} catch (error) {
// you can set some error message state here and show it to the user if you want.
console.log(error);
} finally {
setIsLoading(false);
}
};
getUser();
}, []);
if (isLoading) return <h1>loading</h1>;
return user ? <Outlet /> : <Navigate to="/login" />;
}
Notice I also changed the initial value of the user
state to null
, and changing this value only when the request is a success.