How to dynamically use react routing How to dynamically use react routing reactjs reactjs

How to dynamically use react routing


For better management and development of the program along with thebest practices, Do the Authorization in React.js as follows:

Demo on Codesandbox

First: You need a class for checking permissions and routes/pages configs like below:

class AppUtils {  static setRoutes(config) {    let routes = [...config.routes];    if (config.auth) {      routes = routes.map((route) => {        let auth = config.auth ? [...config.auth] : null;        auth = route.auth ? [...auth, ...route.auth] : auth;        return {          ...route,          auth        };      });    }    return [...routes];  }  static generateRoutesFromConfigs(configs) {    let allRoutes = [];    configs.forEach((config) => {      allRoutes = [...allRoutes, ...this.setRoutes(config)];    });    return allRoutes;  }  static hasPermission(authArr, userRole) {    /**     * If auth array is not defined     * Pass and allow     */    if (authArr === null || authArr === undefined) {      // console.info("auth is null || undefined:", authArr);      return true;    } else if (authArr.length === 0) {      /**       * if auth array is empty means,       * allow only user role is guest (null or empty[])       */      // console.info("auth is empty[]:", authArr);      return !userRole || userRole.length === 0;    } else {      /**       * Check if user has grants       */      // console.info("auth arr:", authArr);      /*            Check if user role is array,            */      if (userRole && Array.isArray(userRole)) {        return authArr.some((r) => userRole.indexOf(r) >= 0);      }      /*            Check if user role is string,            */      return authArr.includes(userRole);    }  }}export default AppUtils;

Second: You need Authorization component for handling routes like below:

import React, { Component } from "react";import AppUtils from "utils/AppUtils";import { matchRoutes } from "react-router-config";import { withRouter } from "react-router-dom";import AppContext from "context/AppContext";class AppAuthorization extends Component {  constructor(props, context) {    super(props);    const { routes } = context;    this.state = {      accessGranted: true,      routes    };  }  componentDidMount() {    if (!this.state.accessGranted) {      this.redirectRoute();    }  }  componentDidUpdate() {    if (!this.state.accessGranted) {      this.redirectRoute();    }  }  static getDerivedStateFromProps(props, state) {    const { location, userRole } = props;    const { pathname } = location;    const matched = matchRoutes(state.routes, pathname)[0];    return {      accessGranted: matched        ? AppUtils.hasPermission(matched.route.auth, userRole)        : true    };  }  shouldComponentUpdate(nextProps, nextState) {    return nextState.accessGranted !== this.state.accessGranted;  }  redirectRoute() {    const { location, userRole, history } = this.props;    const { pathname, state } = location;    const redirectUrl = state && state.redirectUrl ? state.redirectUrl : "/";    /*        User is guest        Redirect to Login Page        */    if (!userRole || userRole.length === 0) {      history.push({        pathname: "/login",        state: { redirectUrl: pathname }      });    } else {      /*        User is member        User must be on unAuthorized page or just logged in        Redirect to dashboard or redirectUrl        */      history.push({        pathname: redirectUrl      });    }  }  render() {    // console.info('App Authorization rendered', accessGranted);    return this.state.accessGranted ? (      <React.Fragment>{this.props.children}</React.Fragment>    ) : null;  }}// AppAuthorization.defaultProps = {//   userRole: [] // You can manage roles by redux or any state managements// };AppAuthorization.contextType = AppContext;export default withRouter(AppAuthorization);

Third: You need authRoles file or remote for managing roles on client like below:

/** * Authorization Roles */const authRoles = {  admin: ["admin"],  superAdmin: ["superAdmin"],  user: ["user"],  onlyGuest: []};export default authRoles;

Forth: If you want to move forward with this logic, you have to implement the structure of your pages as follows:

src |---pages      |---home           |---HomePage.jsx           |---HomePageConfig.jsx      |      |- The rest of the pages should be implemented in the same way

For example: When you want to implement a page that only the admin can see (admin home page config):

import React from "react";import authRoles from "auth/authRoles";export const AdminHomePageConfig = {  auth: authRoles.admin,  routes: [    {      path: "/admin",      exact: true,      component: React.lazy(() => import("./HomePage"))    }  ]};

Or the home page that everyone can see:

import React from "react";export const HomePageConfig = {  routes: [    {      path: "/",      exact: true,      component: React.lazy(() => import("./HomePage"))    }  ]};

According to the example above, you can enter the auth prop with the role here, to restrict access to the page.

To get a closer look at this logic, I implemented it in the Codesandbox, which you can see via the link below:

Demo on Codesandbox

Notice: The above demo needs to be more complete, and instead of storing user roles in the state, it is better to use state managementpackages (redux, ...) and also perform login operations throughcookies.


Instead of creating a dynamic route, you can create a function that checks auth and redirects on entering the route.

const yourRouter = () => {  // yourAuthLogic  const routeAuth = (Component, props) => {  // redirect logic  // here you use the if/else branching based on auth state to redirect    // if no redirect  return (    <Component {...props} />  )}return (  <Router>    <Switch>      <Route path="/admin" render={() => routeAuth(component, props)} />      <Route path="/superAdmin" render={() => routeAuth(component, props)} />   </Switch> </Router>  )}


The problem is that the DuynamicRoute component returns a Redirect in its top level, but Redirects don't work directly inside a Switch components. This is because a Redirect in a Switch would lead to an infinite redirection loop.To fix this, you should return a top level Route from your custom Route component, while handling the redirection logic between the Route tags.

Also, it's worth mentioning that some routes shouldn't be special protected routes, but regular landing pages, such as the home and login pages.

Here is a sample project based on your CodeSandbox solution:https://codesandbox.io/s/vigilant-feather-jbq4j

I made it so that superAdmin user can access admin level, but not the other way around. A lesser admin cannot access superAdmin content, without changing the active user to a superAdmin.

Here is an additional link with a slight modification to logic, for the use case where you would prefer that admin and superAdmin can't access each-other's protected pages: https://codesandbox.io/s/brave-haze-zsmn9?file=/src/ProtectedRoute.js