react-router4 實現按需加載

按需加載的背景

React Router 是一個很是出色的路由解決方案,同時也很是容易上手。可是當網站規模愈來愈大的時候,首先出現的問題是 Javascript 文件變得巨大,這致使首頁渲染的時間讓人難以忍受。實際上程序應當只加載當前渲染頁所需的 JavaScript,也就是你們說的「代碼分拆" — 將全部的代碼分拆成多個小包,在用戶瀏覽過程當中按需加載。javascript

老的方案

這裏所說的總是指使用react-router低於4的版本。java

在低版本(小於4)的react-router中直接提供了按需加載的方案,示例以下:react

const rootRoute = {
  path: '/',
  indexRoute: {
    getComponent(nextState, cb) {
      require.ensure([], (require) => {
        cb(null, require('components/layer/HomePage'))
      }, 'HomePage')
    },
  },
  getComponent(nextState, cb) {
    require.ensure([], (require) => {
      cb(null, require('components/Main'))
    }, 'Main')
  },
  childRoutes: [
    require('./routes/baidu'),
    require('./routes/404'),
    require('./routes/redirect')
  ]
}

ReactDOM.render(
  (
    <Router history={browserHistory} routes={rootRoute} /> ), document.getElementById('app') );複製代碼

核心代碼是router.getComponent,然而在react-router4中,沒有router.getComponent了,這樣咱們該如何實現按需加載呢?webpack

react-router4的實現方案

根據官網的介紹:git

One great feature of the web is that we don’t have to make our visitors download the entire app before they can use it.
You can think of code splitting as incrementally downloading the app. While there are other tools for the job, we’ll use Webpack and the bundle loader in this guide.github

咱們要藉助bundle-loader來實現按需加載。web

首先,新建一個bundle.js文件:react-router

import React, { Component } from 'react'

export default class Bundle extends React.Component {

    state = {
        // short for "module" but that's a keyword in js, so "mod"
        mod: null
    }

    componentWillMount() {
        this.load(this.props)
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.load !== this.props.load) {
            this.load(nextProps)
        }
    }

    load(props) {
        this.setState({
            mod: null
        })
        props.load((mod) => {
            this.setState({
                // handle both es imports and cjs
                mod: mod.default ? mod.default : mod
            })
        })
    }

    render() {
        if (!this.state.mod)
            return false
        return this.props.children(this.state.mod)
    }
}複製代碼

而後,在入口處使用按需加載:app

// ...

// bundle模型用來異步加載組件
import Bundle from './bundle.js';

// 引入單個頁面(包括嵌套的子頁面)
// 同步引入
import Index from './app/index.js';
// 異步引入
import ListContainer from 'bundle-loader?lazy&name=app-[name]!./app/list.js';

const List = () => (
    <Bundle load={ListContainer}> {(List) => <List />} </Bundle>
)

// ...

    <HashRouter>
        <Router basename="/"> <div> <Route exact path="/" component={Index} /> <Route path="/list" component={List} /> </div> </Router> </HashRouter> // ...複製代碼

webpack.config.js文件配置異步

output: {
    path: path.resolve(__dirname, './output'),
    filename: '[name].[chunkhash:8].bundle.js',
    chunkFilename: '[name]-[id].[chunkhash:8].bundle.js',
},複製代碼

完整代碼示例

bundle.js

react-molin

相關文章
相關標籤/搜索