React Router Dynamic loading component-Adapter mode application

Source: Internet
Author: User
Objective


This article describes how to implement dynamic load components, and illustrates the adapter pattern.


I. Common Routing Example


import Center from 'page/center';
import Data from 'page/data';

function App(){
    return (
        <Router>
          <Switch>
            <Route exact path="/" render={() => (<Redirect to="/center" />)} />
            <Route path="/data" component={Data} />
            <Route path="/center" component={Center} />
            <Route render={() => <h1 style={{ textAlign: 'center', marginTop: '160px', color:'rgba(255, 255, 255, 0.7)' }}>页面不见了</h1>} />
          </Switch>
        </Router>
    );
}




These are the most common React routers. In simple single-page applications, this is ok. Because the bundled single js file bundle.js is only about 200k, after gzip, it does not affect the loading performance much.
However, when the product goes through multiple iterations, additional pages cause the size of bundle.js to continue to grow. At this time, optimization becomes necessary.

How to optimize
An important concept for optimization is to load on demand.
It can be understood in combination with examples: only load the components needed for the current page.

For example, if you are accessing the / center page, you only need to load the Center component. No need to load the Data component.

The industry currently implements the following solutions:

react-router's dynamic route getComponent method (router4 is no longer supported)
Use the react-loadable gadget library
Custom high-order components for on-demand loading
The common point of these solutions is to use webpack's code splitting function (webpack1 uses require.ensure and webpack2 / webpack3 uses import) to split the code.

Next, we will show how to implement on-demand loading with custom high-level components.

Third, custom high-order components 3.1 webpack import method
webpack treats import () as a split point and packs the modules it requests into a single chunk. import () takes the module name as the parameter name and returns a Promise object.

Because import () returns a Promise object, it cannot be used directly by <Router />.

3.2 Encapsulating import () with adapter mode
Adapter pattern (Adapter): The interface of a class is transformed into another interface that the customer wants. The Adapter pattern allows classes that could not work together because of incompatible interfaces to work together.

In the current scenario, what needs to be solved is how to hand over the loaded components to React for update after using import () to load components asynchronously.
The method is also very easy, which is to use state. When the component is loaded asynchronously, the setState method can be called to notify.
Then, according to this idea, create a new high-level component and use the adapter pattern to encapsulate import ().

3.3 Implementing the asynchronous loading method asyncComponent



import React from 'react';

export const asyncComponent = loadComponent => (

    class AsyncComponent extends React.Component {
        constructor (... args) {
            super (... args);
    
            this.state = {
                Component: null,
            };

            this.hasLoadedComponent = this.hasLoadedComponent.bind (this);
        }
        componentWillMount () {
            if (this.hasLoadedComponent ()) {
                return;
            }
    
            loadComponent ()
                .then (module => module.default? module.default: module)
                .then (Component => {
                    this.setState ({
                        Component
                    });
                })
                .catch (error => {
                    / * eslint-disable * /
                    console.error ('cannot load Component in <AsyncComponent>');
                    / * eslint-enable * /
                    throw error;
                })
        }
        hasLoadedComponent () {
            return this.state.Component! == null;
        }
        render () {
            const {
                Component
            } = this.state;

            return (Component)? <Component {... this.props} />: null;
        }
    }
);
// how to use

const Center = asyncComponent (() => import (/ * webpackChunkName: 'pageCenter' * / 'page / center'));



As shown in the example, create a new asyncComponent method to receive the Promise object returned by import ().
When componentWillMount (the server-side rendering also has this lifecycle method), execute import (), and set the asynchronously loaded component to the state to trigger the component to re-render.

3.4 Doubt
state.Component initialization
this.state = {
    Component: null,
};
The null here is mainly used to determine whether the asynchronous component has been loaded.

module.default? module.default: module
This is to be compatible with the two export methods named and default.

return (Component)? <Component {... this.props} />: null;
The null here can actually be replaced with <LoadingComponent />. The effect is: when the asynchronous component has not been loaded well, it plays a placeholder role.
this.props is transparently passed to the asynchronous component through the AsyncComponent component.

3.5 Modify webpack build
output: {
    path: config.build.assetsRoot,
    filename: utils.assetsPath ('js / [name]. [chunkhash] .js'),
    chunkFilename: utils.assetsPath ('js / [id]. [chunkhash] .js')
}
In the output, you can add chunkFilename.

Summary
The benefit of custom high-level components is that you can optimize existing legacy projects with minimal changes.
Like the example above, you only need to change the way the import component is. For the least cost, you can get page performance improvements.
In fact, react-loadable is also implemented in this way, but it only adds a lot of auxiliary function points.

reference
On-demand loading of react components based on webpack code splitting
Implementation of loading components asynchronously using webpack2's import () in react

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.