preface

In the past, VUE was used for development, so I decided to do react after the New Year, so I kept messing around with React after the New Year, so I can see the results

I thought I’d write a project like Vue’s toutiao to start with, but then I thought I’d write a back office. Then began to tinker.

Use the React eco-chain module:

  • react
  • react-dom
  • react-router-domReact-router4 looks like it’s going to be used all the time
  • react-transition-group: for animation
  • redux: Used to manage global status
  • react-redux: Used to manage global status
  • redux-actions: used to create the action, and generate the related reducers do not write switch/case or if/else, mainly convenient.
  • redux-thunk: reduxMiddleware to handle our asynchronous actions
  • antdA common react-UI library

Webpack configuration is basically the same as vUE configuration.

File directory explanation:

  • build: used to place configuration about Webpack
  • config: Project Configuration
  • src: the source code
  • staticStatic resource
  • .babelrc: Babel configuration
  • postcss.config.jsConfiguration: CSS

There are no other directories, but I will introduce onesrcDirectory structure under

  • actions: Puts the action related place in redux
  • reducers: Reduce the reducer related areas in redux
  • assets: Project static resources
  • components: Common components commonly used
  • router: Indicates routing configurations
  • store: Redux configuration
  • styles: public style file
  • utils: Encapsulation of utility classes
  • view: The body structure of all pages
  • main.js: Project entry file
  • config.js: Public attribute configuration

1. React

  • React.createClass
import React from 'react'
const MyComponent = React.createClass({
   render () {
       return(<h2> I am the component generated by React. CreateClass </h2>)}})Copy the code
  1. React.createclass will self-bind function methods (unlike react.componentwhich only binds functions of interest), resulting in unnecessary performance overhead and increasing the likelihood of code obsolescence
  2. React. CreateClass mixins are not natural and intuitive;

  • React.Component
import React from 'react'
class MyComponent from React.Component {
    render () {
        return(<h2> I am a component generated by React.Component </h2>)}}Copy the code
  1. You need to manually bind the this pointer
  2. The React.Component form is well suited to Higher Order Components (HOC), which shows more power than mixins in a more intuitive form, and HOC is pure JavaScript, so don’t worry about them being obsolete

  • Stateless functional components
import React from 'react'Const MyComponent = (props) => (< h2> I'm a stateless function </h2>) reactdom.render (<MyComponent name="Sebastian" />, mountNode)
Copy the code
  1. The creation of stateless components makes the code more readable and reduces the amount of redundant code down to a single render method, greatly increasing the ease of writing a component
  2. Components are not instantiated and overall rendering performance is improved
  3. The component cannot access this object
  4. The component cannot access life-cycle methods
  5. Stateless components can only access input props, and the same props will get the same render without side effects

2. Route interception

Vue beforeRouter is a hook function that is similar to vue beforeRouter.

Then I went to the history module and found that there was a method for listening routes. I used it at the beginning, but when I suddenly cut to hash mode for development, I found that there was a problem with setting the state attribute through history.push(path, [state]). This thing seems to only set the state attribute for history mode, but I had some things that came in by setting the state attribute, so I abandoned this method and looked for a new method.

Found behind can be monitored root componentWillReceiveProps hook function Can achieve the result of listening.

This hook function is triggered whenever props changes, because the pathname of location is always different every time you switch routes, so any time you switch paths, this hook function is triggered. These things tend to trigger an endless loop, so use your judgment.

class MainComponents extends React.Component {
    componentWillMount() {/ / for the first time in triggering this. DataInit (enclosing props)} componentWillReceiveProps (nextProps) {/ / after each change props will trigger / / if the infinite loop This. DataInit (nextProps)} this. DataInit (nextProps)}render () {
        // 404
        if(! isExistPath(allRoutes, pathname))return <Redirect to='/error/404'/> // Current path routing informationletCurrRoute = getRoute(allRoutes, pathName) // Non-whitelist verificationif(! Whitelist.some (path => path === pathName)) {// Login authenticationif(! Cookie.get('Auth_Token')) {
                return <Redirect to={{ pathname: '/login'}} />} // Get user informationif(! user) { this.getUserInfo(() => { this.setRoutesByRole(this.props.user.roles) }) } } // 401if (user && currRoute) {
            if(! isAuth(currRoute.role, user))return <Redirect to='/error/401'/>
        }

        // 网页title
        document.title = currRoute.name
    }
}

Copy the code

3. Set the routing set

Those of you who have used VUE know that we use the new Router({routes}) to centrally manage routing tables. The React-router does not seem to work this way. The latest version doesn’t even seem to be nested. So they began to build a simple version of the centralized Settings. There is a plugin that can manage react-router-config, but I haven’t tried it yet and I don’t know if it works.

// Routing table const allRoutes = [{path:'/auth',
    login: true,
    layout: true,
    icon: 'user',
    name: 'Permission Management',
    role: ['admin'],
    component: _import_views('Auth')
  },
  {
    path: '/error',
    login: true,
    layout: true,
    icon: 'user',
    name: 'ErrorPage',
    redirect: '/error/404',
    children: [
        { path: '/error/404', component: _import_views('Error/NotFound'), name: '404'},
        { path: '/error/401', component: _import_views('Error/NotAuth'), name: '401'}}]... ] // Root directory <BrowserRouter> <Route path="/" component={MainComponents}/>
</BrowserRouter>

// MainComponents
class MainComponents extends React.Component {
  render () {
    return( <Switch> {renderRouteComponent(allRoutes.filter(route => ! Route.layout))} // A routing page that does not require a common part such as a sidebar < route path="/" component={ComponentByLayout}/>
      </Switch>
    )
  }
}

// ComponentByLayout
const ComponentByLayout = ({history}) => (
  <Layout history= {history}> <Switch> {renderRouteComponent(allroutes.filter (route => route.layout))} </Switch> </ layout >) // Route render const RouteComponent = route => <Route key={route.path} exact={route.exact ||false} path={route.path} component={route.component} /> 
const renderRouteComponent = routes => routes.map((route, index) => {
    return route.children ? route.children.map(route => RouteComponent(route)) : RouteComponent(route)
})
Copy the code

4. Dynamically generate routes based on user permissions

I want to generate different sidebars based on the user’s different permissions.

{
  path: '/auth',
  login: true,
  layout: true,
  icon: 'user',
  name: 'Permission Management',
  role: ['admin'],
  component: _import_views('Auth')}Copy the code

Display and hide the route based on the role information matching the user’s role information

To filter out the routing table and the sidebar that matches the user (the sidebar is generated from the routing table)

But there was a problem, because we needed to log in to get the user’s permission information, so we had to figure out what the route was at that time.

But by that time the route has already been set up. Vue provides router. AddRoutes to dynamically set routes. React doesn’t have this API either, so I register all routes, but this creates a problem.

In the case of /auth, I don’t have access to /auth, so I don’t generate a list option for /auth in my sidebar. But we can get to the page by accessing /auth from the address bar (it’s best not to generate the route at all). I don’t know how to dynamically generate routes. I’m just doing permission processing in the root directory

5. Load as needed

There are many ways to load on demand, so I only tried the first one so far, because I wrote Vue using import to load on demand, so I didn’t bother.

1. The import method

//asyncComponent.js
import React from 'react'
export default loadComponent => (
    class AsyncComponent extends React.Component {
        state = {
            Component: null,
        }
        async componentDidMount() {
            if(this.state.Component ! == null)return

            try {
                const {default: Component} = await loadComponent()
                this.setState({ Component })
            }catch (err) {
                console.error('Cannot load component in <AsyncComponent />');
                throw err
            }
        }

        render() {
            const { Component } = this.state
            return(Component) ? <Component {... this.props} /> : null } } ) // index.js import asyncComponent from'./asyncComponent.js'
const _import_ = file => asyncComponent(() => import(file))
_import_('components/Home/index.js')
Copy the code

The principle is simple:

  • Import () takes the corresponding module and returns a Promise object
  • The asyncComponent receives a function that returns a Promise object
  • In componentDidMount the hook function executes the incoming loadComponent method via async/await, gets the result returned by import, assigns to state.componentPonent,
  • Since we import a React component, we get the React component as well, so we just need to render the component

2. Bundle component + import (similar to the first feeling)

3. react-loadable

4. bundle-loader

6. request

I’m using Axios here, and I’m using Axios to make a simple interceptor

import axios from 'axios'
import qs from 'qs'


axios.defaults.withCredentials = true/ / send axios. Interceptors. Request. Use (config = > {/ / initiate the request, what can be animatedreturn config
}, err => {
    returnPromise. Reject (err)}) / / response axios. Interceptors. Response. Use (response = > response, Err => promise.resolve (err.response)) // Check the status codefunctionCheckStatus (res) {// Get the result, end the animationif (res.status === 200 || res.status === 304) {
        return res.data
    }
    return {
        code: 0,
        msg: res.data.msg || res.statusText,
        data: res.statusText
    }
    returnRes} // Check the CODE valuefunction checkCode(res) {
    if (res.code === 0) {
        throw new Error(res.msg)
    }
    
    return res
}

export default {
    get(url, params) {
        if(! url)return
        return axios({
            method: 'get',
            url: url,
            params,
            timeout: 30000
        }).then(checkStatus).then(checkCode)
    },
    post(url, data) {
        if(! url)return
        return axios({
            method: 'post',
            url: url,
            data: qs.stringify(data),
            timeout: 30000
        }).then(checkStatus).then(checkCode)
    }
}

Copy the code

7. redux

So we’re basically using redux-Actions, the native way to create actions

// action
const addTodo = text => ({
    type: 'ADD_TODO',
    payload: {
      text,
      completed: false
    }
})

// reducer
const todos = (state = [], action) => {
    switch(action.type) {
        case 'ADD_TODO':
            return [...state, action.payload]
        ...
        default:
            return state
    }
}
Copy the code

Redux-Actions

import { createAction, handleActions } from 'redux-actions'

// action
const addTodo = createAction('ADD_TODO')

// reducer
const todos = handleActions({
    ADD_TODO: (state, action) => {
        return [...state, action.payload]
    }
    ...
}, [])
Copy the code

// Use redux-actions

8. connect

Connect is used to connect components to the Redux store. Connect ([mapStateToProps], [mapDispatchToProps], [mergeProps],[options])

Generally, only the first two parameters are used

  • mapStateToProps(state, ownProps)OwnProps: gets the state data in the store and passes it to the props of the component
  • mapDispatchToPropsGet the action method from the store and pass it to the specified component

usage

import toggleTodo from 'actions/todo'const mapStateToProps = state => ({ active: state.active }) const mapDispatchToProps = { onTodoClick: ToggleTodo} connect(mapStateToProps, mapDispatchToProps)(Component) Same as the onTodoClick methodCopy the code

Connect is basically used in a lot of places so it’s encapsulated

// connect.js
import actions from 'src/actions'// All action import {connect} from'react-redux' 
import {bindActionCreators} from 'redux'
exportDefault connect(state => ({state}), // return all state data to dispatch =>bindActionCreators(Actions, dispatch) // Merge all the actions and pass in the Dispatch so that we can call the action in the component and no longer need dispatch.)Copy the code

bindActionCreators

We then configure the connect.js file with the Webpack alias property

// Configure alias mappingalias: {
    'src': resolve('src'),
    'connect': resolve('src/utils/connect')}Copy the code

Then we can reference it in the file as follows

import React from 'react'
import connect from 'connect'Class Component extends react.component.ponent {componentWillMount () {
    const {state, onTodoClick} = this.props
    console.log(state, onTodoClick)
  }
}
Copy the code

To make things easier, I’ve returned all the store data and actions.

9. cssModules

In VUE we do CSS modularity by setting the scoped property of the style tag, but in React I use cssModules to do CSS modularity

  1. throughwebpackSet up thecss-loadermodulesTo enable the modularity of CSS
{
    loader: 'css-loader',
    options: {
      modules: true, // Whether to enablelocalIdentName: '[name]__[local]___[hash:base64:5]'}};Copy the code
  1. Introduce CSS and add className via object assignment
import styles from './styles.css'

export default () => (
  <div className={styles.a}></div>
)

//styles.css
.a {
    color: #ff4747;
}

Copy the code

Alternatively, you can use react-CSS-modules to control the class name more conveniently

import styles from './styles.css'
import CSSModules from 'react-css-modules'

class Component extends React.Component {
  render () {
    return (
      <div styleName='a b'></div>
    )
  }
}
export default CSSModules(Component, styles, {
    allowMultiple: true}) // styles.css. a {color:#ff4747;
}
.b {
  background: #f00;
}
Copy the code

So we can pass in the class name as a string. Note: Instead of using className, we add styleName

10. Implementation of bidirectional binding

class Bingding extends React.Component {
  state = {
    value: ' '
  }
  handleInput = value => {
    this.setState({
      value
    })
  }
  render () {
    return (
      <input type="text" value={this.state.value} onChange={e => {this.handleInput(e.target.value)}}/>
      <div>{this.state.value}</div>
    )
  }
}
Copy the code

The onChange event triggers this.setState to re-render the render method

There are a few other things that we can talk about animation, life cycle and so on. There’s a little bit of convergence in all of these projects. There are a lot of problems in the development, the most important is the react-router configuration problem, how to configure the feeling is not good. We are also looking for recommendations for several comprehensive, especially the latest, react open source projects.

Project startup Steps

  1. NPM/YARN Run DLL (DllPlugin package, only need to package once)
  2. NPM/YARN Run Dev (Development mode)
  3. NPM/YARN Run Build (Production mode)

summary

I have come into contact with the two popular frameworks in China. I have been using VUE and just got to know React after the New Year. From what I’ve seen so far, VUE is a lot easier to develop than React (probably a lot more). Because many of vue’s common uses are built in. React basically has to find the corresponding module by itself. You just provide the UI, and you basically have to do everything else by yourself. The main thing is that you often find multiple modules, you don’t know which one to use, and you have to test the waters one by one. Of course, the React community is strong, so this isn’t a big deal.

Online viewing address

Blog address

github