When I try to reload any protected page or paste the URL in browser I get redirected to dashboard. I understand from my setup that on reload the isAuthenticated sate is false because of which the protectedRoute component redirects to login page and when the user state is finally set from localstorage the publicRoute component wrapping login page redirects to dashboard.
how can I prevent this redirection problem when user is authenticated and still make sure that user can’t visit login pages when he is already authenticated
i have a publicroute component like this which is supposed to prevent a user from visiting login related page when he is already logged in
/* eslint-disable react/jsx-no-useless-fragment */
import { ReactNode, useEffect } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import { useAppSelector } from '../../redux/hooks';
import { PageLoader } from 'project/spinner';
interface PublicRouteProps {
children: ReactNode;
}
const PublicRoute: React.FC<PublicRouteProps> = ({ children }) => {
const navigate = useNavigate();
const location = useLocation();
const isAuthenticated = useAppSelector((state) => state.user.isAuthenticated);
console.log("location.pathname", location.pathname)
useEffect(() => {
// Redirect to dashboard or prev page if the user is already authenticated
if (isAuthenticated) {
const previousPath = location.state?.from || '/pages/dashboard';
console.log("****************redirecting to dashboard***************");
navigate(previousPath, { replace: true });
}
}, [isAuthenticated, navigate, location]);
return !isAuthenticated ? <>{children}</> : <PageLoader />;
};
export default PublicRoute;
and another ProtectedRoute component for protecting routes from unauthenticated users like this
/* eslint-disable react/jsx-no-useless-fragment */
import { ReactNode, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { useAppSelector } from '../redux/hooks';
import { PageLoader } from 'project/spinner';
interface ProtectedRouteProps {
children: ReactNode;
}
const ProtectedRoute: React.FC<ProtectedRouteProps> = ({ children }) => {
const navigate = useNavigate();
const isAuthenticated = useAppSelector((state) => state.user.isAuthenticated);
console.log('isAuthenticated', isAuthenticated);
useEffect(() => {
// Redirect to login if the user is not authenticated
if (!isAuthenticated) {
console.log('******************redirecting to login********************');
navigate('/');
}
}, [isAuthenticated, navigate]);
return isAuthenticated ? <>{children}</> : <PageLoader />;
};
export default ProtectedRoute;
I also have routes setup like this ,where index(“/”) is a login route
const router = createBrowserRouter([
{
path: `${import.meta.env.BASE_URL}`,
element: (
<Suspense fallback={<PageLoader />}>
<PublicRoute>
<Login />
</PublicRoute>
</Suspense>
),
},
{
path: `${import.meta.env.BASE_URL}/forgot-password`,
element: (
<Suspense fallback={<PageLoader />}>
<PublicRoute>
<ForgotPassword />
</PublicRoute>
</Suspense>
),
},
{
path: `${import.meta.env.BASE_URL}/verify-otp`,
element: (
<Suspense fallback={<PageLoader />}>
<PublicRoute>
<OtpInput />
</PublicRoute>
</Suspense>
),
},
{
path: `${import.meta.env.BASE_URL}/set-password`,
element: (
<Suspense fallback={<DashboardSkeleton />}>
<SetPassword />
</Suspense>
),
},
{
path: 'pages',
element: (
<Suspense fallback={<DashboardSkeleton />}>
<ProtectedRoute>
<App />
</ProtectedRoute>
</Suspense>
),
errorElement: (
<Suspense fallback={<DashboardSkeleton />}>
<ErrorPage />
</Suspense>
),
children: [/////rest of the routes],
},
]);
the setup to load user from local storage on app load
//// user state example
const initialState: UserState = {
isAuthenticated: false,
userInfo: undefined,
currentRole: undefined,
roles: undefined,
permissionGroups: undefined,
};
const AppInitializer = ({ children }: { children: React.ReactNode }) => {
const dispatch = useAppDispatch();
useEffect(() => {
dispatch(loadUserFromLocalStorage()); //Load user from local storage and sets the auth and user state
}, [dispatch]);
return <div>{children}</div>;
};
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<StrictMode>
<Provider store={store}>
<QueryClientProvider client={queryClient}>
<AppInitializer>
<RouterProvider router={router} />
</AppInitializer>
</QueryClientProvider>
</Provider>
</StrictMode>
);