How to dynamically use react routing

For better management and development of the program along with the best 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 management packages (redux, ...) and also perform login operations through cookies.