React-router is an important part of the React ecosystem. Nowadays, routes for single-page applications of React are mostly managed by the front end, rather than by the back end. The React-Router library is commonly used to manage routes. This article tries to write about the Use of the React-Router, but the API is too dull, and the official documentation is well documented. I will use a common development scenario to see how the React-Router is used. Our general system will have user access restrictions, some pages may require users to have a certain permission to access. This paper uses React-Router to implement a front-end authentication model.

All the code for this article has been uploaded to GitHub, you can take it down to play:Github.com/dennis-jian…

The sample application

The function to be implemented in this article is a common scenario, that is, to control different user roles to access different pages, there are four pages in total:

  1. /index: Homepage
  2. /login: the login page
  3. /backend: Background page
  4. /admin: Management page

There are three other roles:

  1. Unlogged user: Access only the home page of the website/indexAnd the login page/login
  2. The average user: You can visit the homepage of the website/indexThe login page/loginAnd background page/backend
  3. The administrator: You can access the management page/adminAnd all the other pages

The introduction of the React – the Router

To implement route authentication, we need to build a simple project with these pages using the React-Router. We created a new project using create-react-app and created a Pages folder with the pages we described earlier:

Let’s first write a simple page, first write a title, such as this:

import React from 'react';

function Admin() {
  return (
    <h1>Administrator page</h1>
  );
}
Copy the code

Several other pages are similar.

The new react-router separates the core logic layer from the display layer. The core logic handles route matching and so on. The react-Router does not only support browsers, but also needs to support React Native. The react-Router does not support browsers, so there are several packages under the react-Router:

React-router: Core logic processing that provides some common base classes

React-router-dom: implements browser-specific route listening and redirecting

React-router-native: implements RN-related route listening and redirecting

In practice, we don’t need to refer to the react-router. Instead, we use the react-router-dom, which references the react-router itself. Let’s introduce react-router-dom in our project.

import React from 'react';
import {
  BrowserRouter as Router,
  Switch,
  Route,
} from "react-router-dom";
import Home from './pages/Home';
import Login from './pages/Login';
import Backend from './pages/Backend';
import Admin from './pages/Admin';

function App() {
  return (
    <Router>
      <Switch>
        <Route path="/login" component={Login}/>
        <Route path="/backend" component={Backend}/>
        <Route path="/admin" component={Admin}/>
        <Route path="/" component={Home}/>
      </Switch>
    </Router>
  );
}

export default App;
Copy the code

You can then add links to other pages in the Home page with Link:

import React from 'react';
import { Link } from 'react-router-dom';

function Home() {
  return (
    <>
      <h1>Home page</h1>
      <ul>
        <li><Link to="/login">The login</Link></li>
        <li><Link to="/backend">The background</Link></li>
        <li><Link to="/admin">The administrator</Link></li>
      </ul>
    </>
  );
}

export default Home;
Copy the code

So far our application runs like this:

Module partition

Although our jump is implemented, everyone can access any page, our previous requirement is to restrict access to the page according to the login role, before writing the code, let’s think about how to do this. Of course, the most intuitive and simple method is to detect the role of the current user on each page, failing to match the error or jump back to the home page. We only have a few pages now, which is fine, but as our application gets bigger and more pages, checking each page once becomes repetitive, so we need to think about this in a different way.

A closer look shows that we have three roles in total, corresponding to three different permissions. The three permissions are hierarchical. The high-level permissions include the low-level permissions, so our page can also be divided into three types according to these permissions:

  1. Public page: All people can access, not logged in can also access, including the website home page and login page
  2. Average page: A page accessible to common login users
  3. Administrator page: A page that only administrators can access

In order to manage these three pages, we can extract them into three files and put them in an independent folder routes. The three files are named publicroutes. js, privateroutes.js and adminroutes.js respectively:

For each route file, we can organize such routes into arrays and export them to external calls, such as publicroutes.js:

import Login from '.. /pages';
import Home from '.. /pages/Home';

const publicRoutes = [
  {
    path: '/login'.component: Login,
    exact: true}, {path: '/'.component: Home,
    exact: true,},];export default publicRoutes;
Copy the code

Then the place we use outside is directly changed to:

import publicRoutes from './routes/publicRoutes';

function App() {
  return (
    <Router>
      <Switch>{publicRoutes.map( ({path, component, ... routes}) =><Route key={path} path={path} component={component} {. routes} / >
        )}
        <Route path="/backend" component={Backend}/>
        <Route path="/admin" component={Admin}/>
      </Switch>
    </Router>
  );
}
Copy the code

Instead of having a long list of routes in app.js, we just loop through an array. However, we can’t render the Route component directly for login pages and admin pages. It’s better to encapsulate an advanced component and put authentication into this component so that our normal pages don’t need to worry about authentication when implemented.

Encapsulating advanced components

It is easy to encapsulate the authentication component. In the previous section, we used publicRoutes directly to loop the Route component. Our authentication component only needs to add a logic on this basis: Before rendering the real Route component, check whether the current user has the corresponding permissions. If so, directly render the Route component. If not, return a page, which can be the login page or the background home page, according to your own project requirements. The route configuration files privateroutes.js and adminroutes.js have two more parameters than publicroutes.js:

// privateRoutes.js
import Backend from '.. /pages/Backend';

const privateRoutes = [
  {
    path: '/backend'.component: Backend,
    exact: true.role: 'user'.// Role permissions required by the current route
    backUrl: '/login'   // Routes that do not meet permission redirect requirements},];export default privateRoutes;
Copy the code

Adminroutes.js is similar:

// adminRoutes.js
import Admin from '.. /pages/Admin';

const adminRoutes = [
  {
    path: '/admin'.component: Admin,
    exact: true.role: 'admin'.// The required permission is admin
    backUrl: '/backend'  // Jump back to background page},];export default adminRoutes;
Copy the code

Then we can write our advanced component, which we’ll call AuthRoute. Note that the backend API will return the role of the current user when we assume that the user is logged in. A user can have multiple roles, such as [‘user’] for a normal user. The administrator role is [‘user’, ‘admin’]. The specific permission validation logic depends on the project permission design. Here is just an example:

// AuthRoute.js
import React from 'react';
import { Route, Redirect } from 'react-router-dom';

function AuthRoute(props) {
  const {
    user: {
      role: userRole
    },
    role: routeRole, backUrl, ... otherProps } = props;// If the user has permission, render the corresponding route
  if (userRole && userRole.indexOf(routeRole) > -1) {
    return <Route {. otherProps} / >
  } else {
    // If you do not have permission, return the configured default route
    return <Redirect to={backUrl} />}}export default AuthRoute;
Copy the code

Then use our AuthRoute render adminRoutes and privateRoutes:

/ /... Omit other code...

{privateRoutes.map(
  (route) = > <AuthRoute key={route.path} {. route} / >
)}
{adminRoutes.map(
  (route) = > <AuthRoute key={route.path} {. route} / >
)}
Copy the code

Login Setting Permission

The user: {role} variable is used in our AuthRoute, but we haven’t set it yet. In real projects, the back-end API returns the role of the current user at login, and the front end stores this permission information in some state management tool, such as Redux. The user configuration is managed using the state of the root component. The two buttons on the Login page change the corresponding state:

import React from 'react';
import { Link } from 'react-router-dom';

function Login(props) {
  const {loginAsUser, loginAsAdmin, history} = props;

  const userLoginHandler = () = > {
    loginAsUser();      // Call the parent method to set user permissions
    history.replace('/backend');     // Go to the background page after login
  }

  const adminLoginHandler = () = > {
    loginAsAdmin();     // Call the parent method to set administrator permissions
    history.replace('/admin');     // The administrator page is displayed
  }

  return (
    <>
      <h1>The login page</h1>
      <button onClick={userLoginHandler}>Common User Login</button>
      <br/><br/>
      <button onClick={adminLoginHandler}>Administrator Login</button>
      <br/><br/>
      <Link to="/">Back to the home page</Link>
    </>
  );
}

export default Login;
Copy the code

At this point, we have completed the simple route authentication. The specific results are as follows:

All the code for this article has been uploaded to GitHub, you can take it down to play:Github.com/dennis-jian…

conclusion

  1. React-RouterCan be used to manage the front-end route jump, yesReactA very important library in ecology.
  2. React-RouterTo support both browsers andReact-NativeHe divided it into three bagsreact-routerThe core package,react-router-domBrowser package,react-router-nativesupportReact-Native. There is no need to import when usingreact-router, just import the required platform packages.
  3. For routes that require different permissions, we can separate them into different classes and create a separate file. If there are not many routes, we can export multiple arrays in a file.
  4. For routes that require authentication, we can use an advanced component to encapsulate the logic of permission verification. Other pages only need to be configured and do not care about authentication at all.

The content of this article is simple, as familiarReact-Router“Is not bad, but we can not only use it, but also know its principle. We’ll look at that in the next articleReact-RouterThe source code contains what mystery, we can point a concern not lost, ha ha ~

The resources

The official document: reactrouter.com/web/guides/…

GitHub source address: github.com/ReactTraini…

At the end of this article, thank you for your precious time to read this article. If this article gives you a little help or inspiration, please do not spare your thumbs up and GitHub stars. Your support is the motivation of the author’s continuous creation.

Welcome to follow my public numberThe big front end of the attackThe first time to obtain high quality original ~

“Front-end Advanced Knowledge” series:Juejin. Cn/post / 684490…

“Front-end advanced knowledge” series article source code GitHub address:Github.com/dennis-jian…