-
Notifications
You must be signed in to change notification settings - Fork 0
Routing
React Router is the most widely adopted routing library in the React ecosystem — and for good reason. It provides a declarative, component-based API for managing navigation, enabling seamless transitions between views without full page reloads.
To install React Router in your project, run:
npm install react-router-domWrap your root component with <BrowserRouter> to enable routing:
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import App from './App';
const root = document.getElementById('root');
ReactDOM.createRoot(root).render(
<BrowserRouter>
<App />
</BrowserRouter>
);This project uses React Router v6 to manage client-side navigation. Routes are defined using the RouteDescription type, which supports metadata such as access control, menu visibility, and offline readiness. The routing system is dynamic, secure, and responsive to user roles and network status.
Routes are composed in two layers:
-
Core route definitions (
routePaths.tsx) -
Runtime router setup (
AppRoutes.tsx)
Routes are declared using the RouteDescription type, which extends React Router's RouteObject with additional fields:
type RouteDescription = {
id: string; // Unique identifier and display name
path: string;
element: React.ReactNode;
icon?: React.ComponentType;
protected?: boolean;
isSideMenu: boolean;
children?: RouteDescription[];
roles?: string[];
offlineReady?: boolean;
offlineOnly?: boolean;
} & RouteObject;{
id: 'Dashboard',
path: '/dashboard',
element: (
<Layout>
<DashboardPage />
</Layout>
),
icon: DashboardReference,
protected: true,
isSideMenu: true,
}{
id: 'Entries',
path: '/entries',
icon: ManageProtection,
element: (
<Layout>
<Outlet />
</Layout>
),
isSideMenu: true,
protected: true,
children: [
{
id: 'Entry List',
path: '', // matches /entries
icon: Table,
element: <ListEntriesPage />,
isSideMenu: true,
protected: true,
},
{
id: 'Entry Details',
path: ':id', // matches /entries/123
element: <DetailsPage />,
isSideMenu: false,
protected: true,
},
],
}- The parent route uses
<Outlet />to render its children. - Child routes use relative paths (
''for the index,:idfor parameters). - Navigating to
/entriesrenders the list;/entries/123renders details.
The routing system supports dynamic filtering based on:
- User roles
- Online/offline status
-
hasAccess(route, isOnline, roles): Determines if a route should be accessible. -
filterRoutesRecursively(routes, isOnline, roles): Recursively filters nested routes. -
getProtectedRoutes(isOnline, roles): Returns all accessible routes for authenticated users. -
getPublicRoutes(): Returns routes available to unauthenticated users. -
getMenuEntries(isOnline, roles): Extracts menu items for the side nav, including nested children.
The AppRoutes component sets up the router using createBrowserRouter and wraps it in a Suspense boundary for lazy loading:
const routesToUse = useMemo(() => {
if (!isLoggedIn) return getPublicRoutes();
return getProtectedRoutes(true, user?.roles || []);
}, [isLoggedIn, user?.roles]);
const browserRouter = useMemo(() => createBrowserRouter(routesToUse), [routesToUse]);
return (
<Suspense fallback={<Loading withOverlay />}>
<RouterProvider router={browserRouter} />
</Suspense>
);-
Define your route in
ROUTES(orSYSTEM_ROUTESfor system pages):- Use a unique
id. - Set the
path(use parameters like:idfor dynamic segments). - Provide the
elementto render. - Optionally set
icon,protected,isSideMenu,roles, etc. - For nested routes, add a
childrenarray.
- Use a unique
-
For nested routes:
- The parent route should use
<Outlet />in itselement. - Child routes use relative paths.
- The parent route should use
-
Access control:
- Set
protected: trueand specifyrolesif needed. - Use
offlineReadyorofflineOnlyfor offline support.
- Set
-
Menu entries:
- Set
isSideMenu: trueto include the route in the side navigation. - Nested menu items are supported via the
childrenfield.
- Set
{
id: 'Settings',
path: '/settings',
element: <SettingsPage />,
icon: SettingsIcon,
protected: true,
isSideMenu: true,
offlineReady: true,
}For a nested route with parameters:
{
id: 'Profile',
path: '/profile',
element: <Layout><Outlet /></Layout>,
isSideMenu: true,
protected: true,
children: [
{
id: 'Profile Details',
path: ':userId',
element: <ProfileDetailsPage />,
isSideMenu: false,
protected: true,
},
],
}- Use
isSideMenu: falsefor routes like login or modal-only views. - The
idfield is used for display and identification (was previouslyname). -
rolescan be used to filter routes based on user permissions. -
offlineReadyandofflineOnlyhelp tailor the UI for offline-first experiences. - You can extend
RouteObjectto include loaders, actions, or error boundaries as needed.