One, foreword

Three articles are planned for this series:

  • 【React series 】 Hand in Hand with the backend System (Architecture)
  • 【React series 】 Redux and Route Authentication
  • 【React series 】 Give you a hand with the backend system (componentized)

Project address: github React-admin

System preview: React-admin system

This series of articles will introduce you to build a highly reusable backend architecture system from scratch, so that everyone can easily build their own backend. The system functions include login authorization, route authentication, and componentization, involving the applications of react-Router and React-Redux. The final effect of the system:

  • Scaffolding environment setup and construction configuration instructions
  • Infrastructure Design
  • Sidebar implementation
  • To solve the routing

React environment setup

2.1 Scaffold Environment

Create a React App. There are three or four ways to create a React App. NPX and NPM are mainly introduced here.

2.1.1 What is NPX?

NPX is a new command added to [email protected]. If your NPM version is later than this, you can use NPX directly. Otherwise, a global installation is required: NPM install -g NPX But my personal recommendation is to upgrade NPM: NPM install -g npm@next.

The vision of NPX is to make the world free of modules that are difficult to call. For example, our project has integrated the Eslint module. To call the module from the command line, we would have to look like this:./node_modules/.bin/ Eslint –init; With NPX, we can just: NPX eslint –init.

At the same time, ** NPX can also avoid global installation, truly belong to the use of go. ** Previously, we used create-react-app to create react applications. The React script was not available until the module was installed globally. NPX create-react-app my-app will download create-react-app to a temporary directory and make the React script available globally. Delete the create-react-app and download it again when needed.

Create this background application using NPX create-react-app my-admin

2.1.2 What happened to NPM Init?

Before @5.2, executing NPM init creates a package.json file in the current directory. For @5.2 and later, we can use the NPM init

command to create an application, for example: NPM init react-app my-app The react-app will automatically complete to create-react-app, and then download and create the app.

NPM init react-app my-admin

2.2 Build configuration

After creating the application in the previous step, the default directory schema looks like this:

npm eject
config
script
webpack

Second, we can also define configuration information in special files: create a new jsconfig.json file and fill it with the following:

{
    "compilerOptions": {
      "baseUrl": "src"// Compile the root path}}Copy the code

2.3 Directory Description

The final directory architecture of our system is as follows:

├─ config // Configure related ├─ script // Build Script ├─ public // Apply External Directory ├─ SRC // source code │ ├─ Components // Public components │ ├─ font // font related │ ├ ─ ─ js / / js library │ ├ ─ ─ the router / / routing related │ ├ ─ ─ SCSS / / stylesheet │ ├ ─ ─ store / / story related │ ├ ─ ─ views/application/page │ ├ ─ ─ index. The js file │ / / entry ├─ ├─ App.js // Main application entryCopy the code

3. Infrastructure

Starting from the main application entry file · app.js ·, according to the layout of our system background, replace the original code with the following code:

import React, { Component } from 'react'
class App extends Component {
  render () {
    return (
      <div className="container">
        <section className="sidebar">Side navigation bar</section>
        <section className="main">
          <header className="header">
            <span className="username">Hi, Ann</span>
          </header>
          <div className="wrapper">The main content</div>
          <footer className="footer">
            <span className="copyright">Copyright @ 2019 songs</span>
          </footer>
        </section>
      </div>)}}export default App
Copy the code

Add styles: Create index.scss in the SCSS directory, delete the app.css file in the root directory (SCSS or other precompiled language is your preference), and add a reference to the stylesheet in index.js. The following results can be obtained:

4. Side navigation bar

4.1 Create the SideBar. Js component in the Components directory and the route configuration file config.js in the router directory. This configuration file is shared by the SideBar and routes:

// Sidebar. Js: Sidebar navigation component. The Sidebar menu is configured in router/config.js
import React, { Component } from 'react'
class SideBar extends Component {
    constructor (props) {
        super(props)
        this.state = {
            routes: []  // Route list
        }
    }
    render () {
        return (
            <ul className="sidebar-wrapper">The sidebar</ul>)}}export default SideBar
Copy the code

4.2 Defining the routing configuration file: Multi-level nesting is supported. Routes and Component cannot coexist at the same level. If there is a sub-menu, use the Routes field; otherwise, use the Component field.

// router/config.js
export default[{title: 'My affairs'.// Page title & level 1 NAV title
        icon: 'icon-home'.routes: [{
            name: 'Pending approval'.// Subnav heading
            path: '/front/approval/undo'./ / url routing
            component: 'ApprovalUndo'  // Routing component
        }, {
            name: 'Processed'.path: '/front/approval/done'.auth: 'add'.// Access the required permissions
            component: 'ApprovalDone'}},// ...
]
Copy the code

4.3 Render the sidebar recursively

// SideBar.js import React, { Component, Fragment } from 'react' class SideBar extends Component { constructor (props) { // ... Enclosing generateSidebar = this. GenerateSidebar. Bind (this)} render () {return (/ / renders the sidebar < ul className = "sidebar - wrapper" > { map(this.generateSidebar, This.state.routes)} </ul>)} generateSidebar (item) {// nav return <li className="sidebar-item" key={item.title}> <div className={ className({ 'sidebar-item-name': true, 'on': <span> {item.title} </span> </div> <ul className="sidebar-sub"> { This.generatesubmenu (item.routes)} </ul> </li>} generateSubMenu(routes) {// subnav return map(each => <li) className="sidebar-sub-item" key={ each.name }> { each.component ? <a href={ each.path }>{ each.name }</a> : ( <Fragment> <div className={ className({ 'sidebar-item-name': true, 'on': {each. Name} </div> <ul className="sidebar-sub"> {this.generatesubmenu (each. Routes)}  </ul> </Fragment> ) } </li>, routes) } }Copy the code

After adding the styles, it looks like this:

SideBar.js

  • checkActive: Detects the close status of menu items according to the current access route.
  • hasPer: Detects whether the current user has access to menu items. If so, render; if not, skip rendering;

5. Basic routes

We need to implement several pages with the react-Router: login, 404, and permission error. These are page-level routes, which can be stored in the views directory. Here, we create the login directory in the Views directory as the login application, and create 404.js and autheror.js in the components directory, and consider them as components:

├──.js // Public components │ ├─.js // Not found │ ├─.js // Permission Error ├─ views // Public components │ ├─.js // Public components │ ├─.js // Public components │ ├─.js // Public components │ ├─.js // Public components │ ├─.js // │ │ ├─ index.js // Login page entryCopy the code

Page.js register route:

// Page.js
import React, { Component } from 'react'
import { BrowserRouter as Router, Switch, Route, Redirect } from 'react-router-dom'
import App from 'App'
import AsyncComponent from 'components/AsyncComponent'
const Login = AsyncComponent((a)= > import(/* webpackChunkName: "login" */ 'views/login'))
const NotFound = AsyncComponent((a)= > import(/* webpackChunkName: "404" */ 'components/404'))
const AuthError = AsyncComponent((a)= > import(/* webpackChunkName: "autherror" */ 'components/AuthError'))
class Page extends Component {
    render () {
        return( <Router> <Switch> <Route exact path="/" render={ () => <Redirect to="/front/approval/undo" push /> } /> <Route path="/front/404" component={ NotFound }/> <Route path="/front/autherror" component={ AuthError } /> <Route Path ="/front/login" render={() => {const isLogin = false <Redirect to="/front/approval/undo" /> : <Login /> } } /> <Route render={ () => <App /> } /> </Switch> </Router> ) } } export default PageCopy the code

The Route interface is used to register routes and define rendering logic. Page.js imports the main App app.js file, so the main entry file index.js needs to import page.js and render it.

Asynchronous components

In the basic routing section of the previous chapter, we used a component function AsyncComponent, which is a factory function that asynchronously parses our component definition. In large applications, we use a lot of asynchronous components, such as () => import(/* webpackChunkName: “Login” */ ‘views/login’) is an asynchronous component that returns a promise. In React, we need to write a factory function to parse the promise and make it available to React. The logic of AsyncComponent is simple: parse and render asynchronously:

// AsyncComponent.js
import React, { Component } from 'react'
export default function asyncComponent (importComp) {
    class AsyncComponent extends Component {
        constructor (props) {
            super(props)
            this.state = {
                component: null}}async componentDidMount () {
            const { default: component } = await importComp()
            this.setState({
                component: component
            })
        }
        render () {
            const C = this.state.component
            return C ? <C {. this.props} / > : null
        }
    }
    return AsyncComponent
}
Copy the code

/front/login, /front/404, /front/autherror The access root path will be redirected to /front/ Approval /undo.

The preceding routes belong to page-level routes and do not require authorization for access. In the next chapter, we will introduce application-level routes and implement route authentication.

Other series

  • 【React series 】 Redux and Route Authentication
  • 【React series 】 Give you a hand with the backend system (componentized)

Project address: github React-admin

System preview: React-admin system