最近在網上也看到了react-router4的好多種按需載入的方法。
傳送門:https://blog.csdn.net/foralienzhou/article/details/73437057
雖然自己的專案不大,但是也要區分前臺和後臺,如果讓訪問前臺的使用者也載入了後臺的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,可以看到在載入最初的頁面時載入的資源如下
而當點選觸發到/dashboard路徑時,可以看到
程式碼拆分在單頁應用中非常常見,對於提高單頁應用的效能與體驗具有一定的幫助。按需載入的方式還不止這一種,還可以使用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;
}
複製程式碼