I have a following Router component:
Router.js
const Router = () => {
const router = createBrowserRouter(RouteList);
return (
<UserProfileProvider>
<RouterProvider router={router} />
</UserProfileProvider>
);
};
export default Router;
routes.js
function withSuspense(Component) {
return (
<SuspenseWrapper>
<Component />
</SuspenseWrapper>
);
}
const RouteList = [
{
path: HomePath,
element: withSuspense(SharedView),
errorElement: withSuspense(ErrorView),
children: [
{
index: true,
element: withSuspense(HomeView),
},
{
path: ManageRolePath,
children: [
{
index: true,
element: withSuspense(ManageRole),
},
{
path: ManageRoleId,
element: withSuspense(ManageRoleInfo),
},
],
},
{
path: AssignRoleToUserPath,
children: [
{
index: true,
element: withSuspense(AssignRoleToUsers),
},
{
path: AssignUserId,
element: withSuspense(UserInfo),
},
],
},
],
},
];
export default RouteList;
const SuspenseWrapper = ({ children }) => {
const { availableScreens } = useContext(UserContext);
const location = useLocation();
const navigate = useNavigate();
const currentPath = location?.pathname?.split("/")[1];
useEffect(() => {
const hasAccessToPage = checkAccesstoPage(currentPath, availableScreens);
if (!hasAccessToPage && availableScreens?.length > 0) {
navigate("/");
}
}, [currentPath, availableScreens, navigate]);
return (
<Suspense fallback={<Loader loadingText="Preparing menu" />}>
{children}
</Suspense>
);
};
export default SuspenseWrapper;
Now here, when I am on the "localhost:3000"
to goes to the home page. Now by using navigation, I am redirecting to a respective page. I am trying to implement a functionality , where if user copy the url and paste it in the browser and if user does not have the access of the page then it should redirect to the home page.
In this case, API response I am setting in the context. Right now, when I do this then it still loads the element with respective to that route.
How do I fix this? I want to element: withSuspense(ManageRole)
render this only if it has the access. On first load it is still showing the route element.
2
Answers
Basically you should wait until you’ve confirmed a user has correct permissions before rendering the protected content. The
SuspenseWrapper
component unconditionally renders itschildren
prop. Refactor theSuspenseWrapper
component to conditionally return the protected content or the redirect, based on access.Example:
It should be noted though that using Higher-Order-Components has fallen a bit out of favor. You also seem to be over-complicating the code just a bit. Instead of wrapping each routed component you could, and should, probably convert the
SuspenseWrapper
into a couple layout route components, one to handle the suspense (e.g. the dynamic imports) and the other to handle route protection.Example:
The Data Routers also support lazily loading routes as well, something like the following:
So If I understand this correctly, (correct me if am wrong), what you want to do is whenever someone lands on your site your app should first check if a user is eligible to go to home page or they should be sent back to login page, so this is how I used to tackle this situation
My Router –
So here I had two routes in my app one was the login route and another was simply the page where files were used to render this was a Notion clone, Let’s say someone directly tried to land on the file page using the URL that contains the id of that file so to tackle this i wrapped my routes in a parent route called outlet, so whenever anyone lands on any of these routes first the parent route or outlet will run
Here is the code of the outlet element i.e Auth component
This code can look a little big at first sight but I’ll break it up for you, so first thing’s first you don’t need to understand the GetLastVisitedFileId function it was made according to my need, so lets just focus on main logic,
Overview
So the first thing that will happen after our application enters this auth component is render something, because that’s how it works, you need to render something whenever a component runs only after that all the functions and useeffects are checked. So if you check the return statement which contains the rendering markup i am checking the value of
AuthCheck
nowAuthCheck
value is not updated yet because no function or use effect has ran yet, so to tackle this i set the initial value ofAuthCheck
as null, and in my rendering logic i mentioned that wheneverAuthCheck
is null just render the loading component , it only contains a loader, now once that is rendered now our useeffect can run ,Authentication Logic
Now for authentication i was using JWT token so if a new user has just came for first time or there JWT is deleted from there storage then obviously there won’t be any JWT token in the storage, so i was checking if JWT is empty then just set the value of
AuthCheck
to false and hence login page gets rendered, else run the Verification function which checks if the Token is correct and validates it , if token gets validated and i get a 200 response from backend then i used to set the value ofAuthCheck
to be true and the corresponding children (Will always be Dashboard component in this case beacause there were not some other routes) used to get rendered.Let me know if you did not understood something