1. 程式人生 > >react-router4的按需載入實踐(基於create-react-app和Bundle元件)

react-router4的按需載入實踐(基於create-react-app和Bundle元件)

最近在網上也看到了react-router4的好多種按需載入的方法。

雖然自己的專案不大,但是也要區分前臺和後臺,如果讓訪問前臺的使用者也載入了後臺的js程式碼,還是很影響體驗的,所以挑了一種按需載入的方法進行實踐(基於create-react-app和Bundle元件)。

import()

這裡的import不同於模組引入時的import,可以理解為一個動態載入的模組的函式(function-like),傳入其中的引數就是相應的模組。例如對於原有的模組引入import react from ‘react’可以寫為import(‘react’)。但是需要注意的是,import()會返回一個Promise物件

。因此,可以通過如下方式使用:

btn.addEventListener('click', e => {
    // 在這裡載入chat元件相關資源 chat.js
    import('/components/chart').then(mod => {
        someOperate(mod);
    });
});

可以看到,使用方式非常簡單,和平時我們使用的Promise並沒有區別。當然,也可以再加入一些異常處理:

btn.addEventListener('click', e => {
    import('/components/chart').then
(mod => { someOperate(mod); }).catch(err => { console.log('failed'); }); });

我們首先需要一個非同步載入的包裝元件Bundle。Bundle的主要功能就是接收一個元件非同步載入的方法,並返回相應的react元件。

import React from 'react';

export default class Bundle extends React.Component {
    constructor(props) {
        super(props);
        this
.state = { 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().then((mod) => { this.setState({ mod: mod.default ? mod.default : mod }); }); } render() { return this.state.mod ? this.props.children(this.state.mod) : null; } }

引入模組的時候需要用Bundle元件包一下

import Bundle from './Bundle'
const Dashboard = (props) => (
    <Bundle load={() => import('./Dashboard')}>
        {(Dashboard) => <Dashboard {...props}/>}
    </Bundle>
);

路由部分沒有變化

<HashRouter>
    <Switch>
        <Route path='/' exact component={Index} />
        <Route path='/dashboard' component={Dashboard} />
    </Switch>
</Router>

這時候,執行npm start,可以看到在載入最初的頁面時載入的資源如下
image

而當點選觸發到/dashboard路徑時,可以看到
image

程式碼拆分在單頁應用中非常常見,對於提高單頁應用的效能與體驗具有一定的幫助。按需載入的方式還不止這一種,還可以使用require.ensure()或者一些loader也可以同樣實現這個功能。
如果載入的js很大,或者使用者的網路狀況不好的話,需要加上一個loading的效果,這裡我用的是antd的Spin元件。在render函式的mod沒set的時候加上就可以了。

render() {
    let spin = <div style={{textAlign: 'center', marginTop:50}}><Spin size="large"/><br/>正在玩命載入中。。。</div>;
    return  this.state.mod ? this.props.children(this.state.mod) : spin;
}

image