Project Preview Address
preface
I believe that many partners are likely to encounter the development of background management system such requirements, so how can we quickly complete this requirement
This paper will take React as the starting point to record the process of creating a basic management system template, so as to deepen the understanding of react technology stack and actual project, and I hope it will be helpful for you to develop such a project
If there are flaws and mistakes in the article, please also see the small partners to give advice, thank you in advance
The following left
Project introduction
React-admin is a background management system template built by create-React-app scaffolding and based on the React ecosystem. Log-in/logout, lazy route loading, AXIOS encapsulation, simple permission management and other functions, it can help you quickly generate management system templates, you only need to add specific business code
Online preview address Preview address
GitHub code address
Technology stack
The technology stacks involved in this project mainly include ES6, React, React-Router, redux, React-Redux, Create React App, React-Loadable, axios, etc., so you may need to know these knowledge in advance. This will help you understand the project a lot
The basic function
- The route was loaded lazily. Procedure
- Breadcrumb navigation
- The commonly used
UI
show echarts
Full screen display- Login/logout function
axios
encapsulation- Simple Rights Management
The project structure
├ ─ ─ the publicResource files that do not participate in compilation├ ─ ─ the SRC# Main program directory│ ├ ─ ─ API# axios encapsulation│ ├ ─ ─ assets# Resource files│ │ ├ ─ ─ the font# font file│ │ └ ─ ─ images# Image resources│ ├ ─ ─ the components# Global public component│ │ ├ ─ ─ CustomBreadcrumb# Breadcrumb navigation│ │ └ ─ ─ CustomMenu# menu menu│ ├ ─ ─ contatiners# Page structure component│ ├ ─ ─ routes# Route directory│ ├ ─ ─ store# redux configuration│ ├ ─ ─ style# Style directory│ ├ ─ ─ utils# tools│ ├ ─ ─ views# the UI pages│ ├ ─ ─ APP. Js# App.js│ └ ─ ─ index. Js# index.js├ ─ ─. Prettierrc. Js# Code specification├ ─ ─ the config - overrides. Js# ANTD styles are loaded on demand
Copy the code
The overall train of thought
Build any project, except for the audience that needs to be considered in the early stage. On top of that, add technology selection, and then you get to the page architecture layer. In this project, the early stage is not on our radar (it has been determined), so we start with the page architecture
A backend management project, whether it has permission validation or not, has some common parts. Such as landing pages, common headers, sidebar navigation, bottom, and error pages. These common parts as well as permissions specific parts together make up the system
After dividing such modules, the basic page architecture of a project is completed, because this part relates to our definition of page routing later, so I think it is an important part
routing
Based on the [email protected]
The routing function can be said to be the key of a React project. By dividing the page architecture above, we can smoothly register the routing
basic
In the React-admin project, the
was used.
First, we need to distinguish between public pages and possibly unique pages
<Router>
<Switch>
<! Is the exact match on the home page -->
<Route path='/' exact render={()= > <Redirect to='/index' />} / ><! -- Error page -->
<Route path='/ 500' component={View500} />
<Route path='/login' component={Login} />
<Route path='/ 404' component={View404} />
<! -- UI page -->
<Route path='/' component={DefaultLayout} />
</Switch>
</Router>
Copy the code
We can then register the routing table and loop through it to our viewport page. You may also have noticed the term loop traversal. Manipulating an array means that we can do a series of filters on it to control routing permissions (which we’ll talk about later).
Lazy loading
As a SPA-level application, there are many advantages (faster response, good front and rear end separation, etc.), but there are also many drawbacks, such as long first load times, which we had to deal with
Since webpack4.0, it has implemented on-demand loading of components, but it has its own rules (such as file size), so we still need to do something with the first page load, and routing is a good place to start
React-loadable is used in this project, which can realize lazy loading of routes in a very simple way, setting the delay time, loading animation, server rendering and other functions
import Loadable from 'react-loadable';
import Loading from './my-loading-component'; Loading const LoadableComponent = Loadable({loader: () => import('./my-component'),
loading: Loading,
});
export default class App extends React.Component {
render() {
return<LoadableComponent/>; }}Copy the code
Of course, you can also use React. Lazy and Suspense techniques (portals), however, it does not support server rendering
The login
The logon logic is simple:
The home page of our project is usually the index page. At this time, we need to first determine whether a user is in the login state when loading in. If so, it will be displayed normally
In this project, the login information of the user is stored in localStorage, and the localStorage is cleared when the user logs out
The token can be directly stored in the local, the background set an expiration time can be
In another case, after the user logs in, the token expires because there is no operation for a long time. In this case, there may be two options:
- Let the user directly go to the login page to log in again
- Check whether the local storage user information, if yes, update the user information
token
To continue, or to go to the login page (depending on where you store the user information)
Of course, exactly how to do it depends on the demand of the product, but this is just an idea, right
Axios encapsulation
Basic operation
The project uses AXIos to interact with the background, encapsulating functions such as adding request interceptors, response interceptors, setting response times, and adding tokens to requests
import axios from 'axios'
// This depends on where to store the token during login
const token = localStorage.getItem('token')
const instance = axios.create({
timeout: 5000
})
// Set the POST request header
instance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'
// Add a request interceptor
instance.interceptors.request.use(
config= > {
// Add the token to the request header
token && (config.headers.Authorization = token)
return config
},
error => {
return Promise.reject(error)
}
)
// Add a response interceptor
instance.interceptors.response.use(
response= > {
if (response.status === 200) {
return Promise.resolve(response)
} else {
return Promise.reject(response)
}
},
error => {
// Appropriate error handling
// For example: token expired, no access permission, path does not exist, server problem, etc
switch (error.response.status) {
case 401:
break
case 403:
break
case 404:
break
case 500:
break
default:
console.log('Other error messages')}return Promise.reject(error)
}
)
export default instance
Copy the code
BaseUrl is not set here, mainly considering that there may be more than one URL in the project, such as pictures and other resources may exist on servers such as Qiniuyun or Aliyun, while the background interface is another URL. So a config file was added to export the individual urls
// Consider that the site may have several domain names, so mention them separately
export const API = 'http://rap2api.taobao.org/app/mock/234047'
export const URLAPI = ' '
Copy the code
You can just do that when you call the interface
import {API} from './api/config'
import axios from './api'
axios.get({
url: API + '/login'
})
Copy the code
Of course, if you do not have such a requirement, you can cancel the config file and encapsulate the baseUrl
Similarly, common requests such as GET, POST, and so on are not encapsulated, because these methods may be used to do some specific operations on the data, such as serialization, and so on, so personal sense is not very significant
Cross domain
Here, by the way, is a note of how cross-domain problems are solved:
If you don’t use NPM run eject to expose the webPack configuration, you can configure the proxy directly in package.json
"proxy": {
"/api": {
"target": "http://100.100.100.100".// Back-end address
"changeOrigin": true}}Copy the code
Just add the/API after baseUrl
Of course, if you expose the configuration in WebPack, you can also set it directly in the Config file to achieve the same effect
permissions
Permission function is basically an indispensable part of background management projects
In general, the control of permissions is reflected in the page level and button level (whether a user can access a page or operate a button, such as add or delete). This permission is determined when the user is registered, assigned, or later changed by the super administrator
Project implementation
In this project to use a simple permission control, I hope to give you some ideas, specific implementation:
- User login, from the background to obtain the registration role (permission ID)
- By permission identification, to the registered
menu
The menu is filtered to render to the page
getMenu = menu= > {
let newMenu,
auth = JSON.parse(localStorage.getItem('user')).auth // Obtain the user permission id of the storage
if(! auth) {return menu
} else {
// Filter the registered menu
newMenu = menu.filter(res= >res.auth && res.auth.indexOf(auth) ! = =- 1)
return newMenu
}
}
Copy the code
- The registered route array is filtered by the permission id
{routes.map(item => {
return (
<Route
key={item.path}
path={item.path}
exact={item.exact}
render={props= >! auth ? (<item.component {. props} / >
) : item.auth && item.auth.indexOf(auth) !== -1 ? (
<item.component {. props} / >) : (// You can also jump to the 403 page<Redirect to='/ 404' {. props} / >
)
}></Route>)})}Copy the code
- Button permission, directly use the permission identifier to determine whether it can be operated, hidden or displayed
Note: Here for the registered route array to filter this step to explain, generally front-end routes are registered in advance, even if there is no menu menu navigation, if we directly input the path in the address bar can also access, here after a filter can avoid this situation. Of course, we can also set an array of access paths for each permission, by comparing whether the jump address exists in the array to display the corresponding
The background control
Here is also a brief background control permissions case, for the front end is much simpler
- The user logs in and gets what needs to be shown
menu
Array, rendering directly to the page (filtering the menu is done in the background) - The user can determine whether the user has the operation permission of a button based on the permission id
As for the user to enter the address directly in the address bar to access, there are two cases:
- If the user does not have access to a page, use it
token
The request for background data must be unsuccessful, we can encapsulate this operation inaxios
In the request, different status codes are used to jump to the page - I just visited an unrequested page (the page is not available to people who do not have permission to see it), so we will filter the permission array to prevent its operation
Of course, the second one here is rare…
other
The project also integrates functional requirements that you might encounter on a regular basis
animation
Animation uses Animate. CSS animation library, the way to use it
/ / download
yarn add animate.css
// The link tag is imported
<link rel="stylesheet" href="animate.min.css">
// Or import import
import 'animate.css'
Copy the code
Then add the corresponding class name on the box you need, you can set the entry, exit animation, animation time, delay and so on
The rich text
The rich text editor uses the official Antd recommendation, Braft-Editor
A draft-Js-based rich text editor for the Web. It works with the React framework and is compatible with mainstream modern browsers
Usage:
/ / introduction
import BraftEditor from 'braft-editor'
/ / can use BraftEditor createEditorState method to raw data into editorState data or HTML format
editorState: BraftEditor.createEditorState('Hello, lovely person! Lucky to meet you here! ')
Copy the code
You can refer to the documentation portal for more details on component properties and instance methods
echarts
Echarts I believe you are not unfamiliar with, Baidu’s documentation is also very clear, here alone to record the main development process encountered a problem
We can use it when the page window changes
window.addEventListener('resize'.function() {
myChart.resize()
})
Copy the code
This ensures that echarts are normally adaptive
The window. Resize method is not triggered when we click the shrink/expand button. The width of the page box has changed, but the echarts resize event has been triggered. At this point, we only need to register a timer in the componentDidUpdate life cycle to trigger the resize event, just don’t forget to clear the timer in the componentWillUnmount life cycle
Loading progress bar
The loading progress bar uses nprogress and is easy to use
/ / download
yarn add nprogress
/ / introduction
import NProgress from 'nprogress'
// Start loading
NProgress.start();
// Loading is complete
NProgress.done();
// Remove the progress bar
NProgress.remove();
Copy the code
Full screen plug-in
The full-screen feature uses the ScreenFull plug-in
use
/ / download
yarn add screenfull
if (screenfull.isEnabled) {
screenfull.request(); / / full screen
}
.exit() / / exit
.toggle() / / the swappable
Copy the code
You can also register a change event for it
if (screenfull.isEnabled) {
screenfull.on('change', () = > {console.log('Am I fullscreen? ', screenfull.isFullscreen ? 'Yes' : 'No');
});
}
Copy the code
But don’t forget to remove this event
screenfull.off('change', callback);
Copy the code
Uniform code format
The Create React App provides a set of the most common error rules that prompt error messages when code is running, so Eslint rules are not required here. If you also want to prompt errors when code is being written, do the following:
Download eslint
yarn add eslint
Copy the code
Add an.eslintrc.js file or add the rules you need to use directly to the eslintConfig object in the package.json file
More rules can be found here
Eslint was not used in the project, but pretter was added to unify the coding style of the project
As for how to integrate Pretter into a project, you can refer to the official document for the specific usage, which will not be described here
Webpack expand
I believe that when you are developing such a project, there will be more or less some customization things need to modify the webPCK configuration
When creating a project using the Create React App, the Webpack configuration is not exposed by default. If we want to change the configuration, we can use yarn eject or NPM run eject to expose it and change it
But what if we want to configure WebPack without exposing it
Antd’s style on demand loading is implemented in this way
React-app-rewired is an open source tool for modifying CRA configurations in the React community, such as extending the Create React App Webpack configuration, Customize-cra provides a set of Create React App configurations for customizing the react-app-rewired core functionality, which can be extended to the WebPack configuration through the config-overrides
Keep it simple: React-app-rewired and Customize-cra fulfill our needs
Usage:
- You must have downloaded these two packages first
- Then create one in our project root directory
config-overrides.js
file
For example, we set an absolute path
const { override, addWebpackAlias } = require('customize-cra')
const path = require('path')
module.exports = override(
addWebpackAlias({
[The '@']: path.resolve(__dirname, 'src')}))Copy the code
- Last modified
package.json
In the filescripts
"scripts": {
"start": "react-app-rewired start"."build": "react-app-rewired build"."test": "react-app-rewired test"."eject": "react-scripts eject"
}
Copy the code
End of story, so we can happily use this @ in our project
Of course, the customize-cra package also provides us with many encapsulated apis, as you can see here
The last
This project was developed in my spare time, mainly to get familiar with react development process and the use of surrounding ecology. The project is still relatively simple, and iterative development will be carried out in the later stage to build it into a more practical background management template
If you feel good or have some help for you, welcome to star, or you have a better way to achieve, interesting idea, also welcome to leave a message exchange
If you are interested, you can click here or scan the qr code below to follow my wechat official account and see more front end snippets. Welcome to star