React Easy Router
react-easy-router is a declarative routing library for React applications that significantly simplifies the configuration of routes by building upon `react-router-dom`. Currently at version 2.2.0, it offers an object-based approach to defining routes, supporting dynamic segments, navigation, redirection, and protected routes with optional role-based access control. Recent releases indicate an active development cycle, with version 2.1.0 converting the entire architecture to TypeScript and subsequent releases adding features like multiple role authentication and type improvements. It differentiates itself by abstracting away much of `react-router-dom`'s direct component usage, providing a more concise API for common routing patterns and built-in authentication hooks. This package requires `react-router-dom` version 6.4.0 or later to be installed as a peer dependency, and the application must be wrapped in `BrowserRouter` externally.
Common errors
-
Error: A <Router> is missing a 'router' prop or a 'history' prop. Please render your <Router> in a React app or use a custom router. Learn more: https://reactrouter.com/docs/en/v6/getting-started/tutorial#wrapping-your-app
cause `react-router-dom`'s `BrowserRouter` component is not wrapping the `react-easy-router`'s `Router` component, which is required since `react-easy-router` v2.0.5.fixWrap your main application component with `<BrowserRouter>` from `react-router-dom`. Example: `<BrowserRouter><App /></BrowserRouter>` -
TypeError: Cannot read properties of undefined (reading 'routes')
cause The `routes` prop was not passed to the `Router` component, or it was passed as `undefined`.fixEnsure you pass a valid array of route objects to the `routes` prop: `<Router routes={myRoutesArray} />`. -
TypeError: Cannot read properties of null (reading 'getItem')
cause The `isAuthenticated` function or other authentication logic attempts to access browser-specific APIs (like `localStorage` or `window`) in a server-side rendering (SSR) environment without proper checks.fixAdd checks for `typeof window !== 'undefined'` before accessing browser-only globals within your authentication functions or route elements.
Warnings
- breaking As of v2.0.5, `react-easy-router` no longer internally uses `BrowserRouter`. Your application must now explicitly wrap its root component in `BrowserRouter` from `react-router-dom`.
- breaking Since v2.0.2, `react-router-dom` (specifically version >=6.4.0) is a mandatory peer dependency. It must be installed in your project for `react-easy-router` to function.
- gotcha The `isAuthenticated` prop expects a function that returns an object like `{ success: true, role: 'yourRole' }` for success, or `false` for failure. Any other return type (e.g., `undefined` or an empty object) might lead to unexpected authentication behavior.
- gotcha A bug in versions prior to v2.1.1 caused all props to be treated as required, even if marked optional. This could lead to validation errors during development.
Install
-
npm install react-easy-router -
yarn add react-easy-router -
pnpm add react-easy-router
Imports
- Router
const Router = require('react-easy-router');import Router from 'react-easy-router';
- RouteObject
import type { RouteObject } from 'react-easy-router'; - AuthFunction
import type { AuthFunction } from 'react-easy-router';
Quickstart
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import Router from 'react-easy-router';
// Placeholder components
const Login = () => <div>Login Page</div>;
const Admins = () => <div>Admins Dashboard</div>;
const Admin = () => <div>Admin Detail</div>;
const Users = () => <div>Users List</div>;
const User = () => <div>User Detail</div>;
const NotFound = () => <div>404 - Page Not Found</div>;
const routes = [
{ path: '/', navigate: '/login' },
{ path: '/login', element: <Login /> },
{
path: '/admins',
element: <Admins />,
children: [{ path: '/admin', element: <Admin /> }],
},
{
path: '/users',
element: <Users />,
children: [{ path: '/user', element: <User /> }],
},
{
path: '/admin',
element: <Admin />,
protected: true,
roles: ['admin', 'manager'], // Optional: Role specific screen
failureRedirect: '/login', // Optional: Default is '/' if not specified
},
{ path: '*', element: <NotFound /> },
];
function App() {
// Function can resolve/reject or return true/false
const checkAuth = () => {
const token = typeof window !== 'undefined' ? localStorage.getItem('token') : null;
// Simulate authentication based on a token and return a role
if (token === 'admin-token') {
return { success: true, role: 'admin' };
} else if (token === 'manager-token') {
return { success: true, role: 'manager' };
} else {
return false; // Not authenticated or no valid token
}
};
return <Router routes={routes} isAuthenticated={checkAuth} />;
}
// Render the app
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
root.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
);