One, what is load on demand
As with the asynchronous load script (asynchronously loading the script method), on-demand load/code cutting can also solve the first screen loading speed.
- When you need to load on demand
If it is a large file, it is appropriate to use on-demand loading. For example, a nearly 1M of national cities and counties of the JSON file, when I load the first screen does not need to be introduced, but when the user click on the option to load. If you do not click, it will not load. You can shorten the number of first-screen HTTP requests and the time.
If it's a small file, you don't have to be too concerned about loading on demand. Excessive HTTP requests can cause performance problems.
Second, the method of implementing on-demand loading
- Webpack Packaging Module Tool implementation
- Requirejs implementation
Here are the React-router+Webpack
features that implement on-demand loading, with the following effects:
Third, the realization process (react-router4.0)
Attention! I am using the latest version of react-router-dom^4.3.1. If it is under 4.0, React-route can look directly at four
4.0 is more complex than the previous implementation. The Bundle-loader module needs to be introduced. and create your own bundle model implementations.
1. Create a wrapper component model Bundle.js
import React from ‘react‘;class Bundle extends React.Component { constructor(arg){ super(arg) this.state = { mod: null, } } componentWillMount() { this.load(this.props); } componentWillReceiveProps(nextProps) { if (nextProps.load !== this.props.load) { this.load(nextProps); } } // load 方法,用于更新 mod 状态 load(props) { // 初始化 this.setState({ mod: null }); /* 调用传入的 load 方法,并传入一个回调函数 这个回调函数接收 在 load 方法内部异步获取到的组件,并将其更新为 mod */ props.load(mod => { this.setState({ mod: mod.default ? mod.default : mod }); }); } render() { /* 将存在状态中的 mod 组件作为参数传递给当前包装组件的‘子‘ */ return this.state.mod ? this.props.children(this.state.mod) : null; }}export default Bundle ;
2. How to create a wrapper component (function)
// 懒加载方法import React from ‘react‘;import Bundle from ‘./Bundle‘;console.log(Bundle);// 默认加载组件,可以直接返回 nullconst Loading = () => <div>Loading...</div>;/* 包装方法,第一次调用后会返回一个组件(函数式组件) 由于要将其作为路由下的组件,所以需要将 props 传入*/const lazyLoad = loadComponent => props => ( <Bundle load={loadComponent}> {Comp => (Comp ? <Comp {...props} /> : <Loading />)} </Bundle>);console.log(lazyLoad);export default lazyLoad; //实际上lazyLoad就是一个函数,组件调用即可
The relationship of the above two files:
Lazyload.js from the name, called lazy loading. is actually the role of a middleware. Finally lazyload exposes a function to be called by the component. Lazyload What to export:
function lazyLoad(loadComponent) { return function(props) { return ( <Bundle load={loadComponent}> {Comp => (Comp ? <Comp {...props} /> : <Loading />)} </Bundle> ) }}
Obviously, LoadComponent is the component to be loaded, called in the route, for example: calling the Page1 component asynchronously
Bundle.js as the core of on-demand loading, the Lazyload middleware has been introduced and passed in a custom method load, the value of which is the component content. and dynamic sub-content children:
{Comp => (Comp ? <Comp {...props} /> : <Loading />)}
Finally, the component information is returned with the corresponding props. If there are no related components, loading
3. Route with
Import React from ' React ', import {Navlink,route,switch,browserrouter as Router} from ' React-router-dom ' import './style/ Style.css ' import ' bundle-loader '//bundle model is used to asynchronously load the component import bundle from '. /routes/bundle.js '; import lazyload from '. /routes/lazyload '; import Page1 from ' Bundle-loader?lazy&name=page1!.. /components/page1/index '; import Page2 from ' Bundle-loader?lazy&name=page2!.. /components/page2/index '; import Page3 from ' Bundle-loader?lazy&name=page3!.. /components/page3/index '; class Apppage extends react.component{constructor (ARG) {super (ARG) this.state={ }} render () {return (<router basename= "/" > <div classname= "appwried") ; <div classname= "appbtn" > <navlink to= "/page1" classname= "button" Activeclassname= "Active" & Gt PAGE1 </NavLink> <navlink to= "/page2" classname= "button"Activeclassname= "Active" > PAGE2 </NavLink> <navlink to= "/page3" classname= "button" Activeclassname= "active" > PAGE3 </NavLink> </div> <route path= "/" Render={props = (<Switch> <rou Te path= "/page1" Component={lazyload (Page1)}/> <route path= "/page2" Component={lazyl Oad (Page2)}/> <route path= "/page3" Component={lazyload (Page3)}/> </Switch>)}/> </div> < /router>)}}export default apppage;
- A few points to note:
- When import asynchronously loads a component, the name changes to ' Bundle-loader?lazy&name=page1!.. /components/page1/index '
where Bundle-loader represents loader: ' Bunle-loader ' (Need to load Bundle-loader module)
Lazy means lazy:true; lazy loading
Name: The name of the file that is generated asynchronously
- Removing the outer route without render rendering is possible
<Switch> <Route path="/page1" component={lazyLoad(Page1)}/> <Route path="/page2" component={lazyLoad(Page2)}/> <Route path="/page3" component={lazyLoad(Page3)}/> </Switch>
//webpack.config.js... module.exports = { ... output:{ path:path.join(__dirname + ‘/dist‘), //打包地方 filename:‘bundle.js‘, //打包名字 publicPath: ‘/‘, //自动生成html引入js的路径 //按需加载 chunkFilename:‘[name]_[chunkhash:8].js‘ }, ... }...
Pay attention to the Publicpath parameter here.
If the Publicpath parameter is not set, the default package generated by the HTML introduces the bundle as:
<script type="text/javascript" src="bundle.js"></script>
If you set Publicpath to Publicpath: '/dist ', then the boxed HTML file is introduced in JS format:
<script type="text/javascript" src="/dist/bundle.js"></script>
Reference article: React-router-v4-webpack for On-demand loading (code-splitting)
On-demand load optimization of front-end performance (React-router+webpack)