在使用Create React App創建的React項目,通常會通過import引用所需的組件(如import HelloWorld from './HelloWorld'),當項目打包成生產環境代碼時,通過這種方式引用的js文件都會被打包到一起。當前端項目代碼量足夠大時,這意味最終打包出來的index.js代碼量也將會非常大,這明顯不利於實現頁面的秒加載。遇到這種場景,懶加載就提供瞭解決方案。懶加載的根本就是代碼分割,它可以將不需要在首屏顯示的組件代碼獨立分割成一個文件,在適當的時候(如經過用戶交互後),再把這類組件動態加載出來。
React實現懶加載有兩種方式:
1. import().then();
import("./math").then(math => {
console.log(math.add(16, 26));
});
以代碼爲例,用方式實現懶加載,在打包時會將import的內容即math.js獨立打包成一個文件,實現與主程序的代碼分割。
在實際應用中,常常會封裝成一個動態加載的高階組件asyncComponent:
import React, { Component } from 'react';
const asyncComponent = (importComponent) => {
return class extends Component {
constructor() {
super();
this.state = {
component: null
};
}
componentDidMount() {
importComponent()
.then(cmp => {
this.setState({ component: cmp.default });
});
}
render() {
const C = this.state.component;
return C ? <C {...this.props} /> : null;
}
};
};
export default asyncComponent;
asyncComponent應用於路由的懶加載實現:
<Switch>
<Route exact path="/" component={AsyncComponent(() => import('./routes/Home'))}></Route>
<Route path="/about" component={AsyncComponent(() => import('./routes/About'))}></Route>
</Switch>
2.React.lazy
React.lazy 接受一個函數,這個函數需要動態調用 import()。它必須返回一個 Promise,該 Promise 需要 resolve 一個 defalut export 的 React 組件。React.lazy通常與React.Suspense配合使用。
import React, { lazy, Suspense } from 'react';
const CompA = lazy(() => import('./CompA'));
class Test extends React.Component {
constructor(props) {
super(props);
}
render() {
const visible = false;
return (
<div>
{visible ?
<Suspense fallback={<div>Loading...</div>}>
<CompA />
</Suspense> : null}
</div>
);
}
}
export default Test;
在上述代碼中,組件CompA不會被馬上加載進來,只有當visible爲true時,纔會被動態加載進來。
當項目打包時,與第一種方式相同,CompA.js會被獨立打包出來,打包出來的文件會通過動態加載的方式引用到項目中。
React.lazy應用於路由懶加載實現:
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import React, { Suspense, lazy } from 'react';
const Home = lazy(() => import('./routes/Home'));
const About = lazy(() => import('./routes/About'));
const App = () => (
<Router>
<Suspense fallback={<div>Loading...</div>}>
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
</Switch>
</Suspense>
</Router>
);