注意: 動態 import() 語法目前只是一個 ECMAScript (JavaScript) 提案, 而不是正式的語法標準。預計在不遠的未來就會被正式接受。react
Webpack 解析到該語法時,它會自動地開始進行代碼分割。若是你使用 Create React App,該功能已配置好,你能馬上使用 這個特性。Next.js 也已支持該特性而無需再配置。 若是你本身配置 Webpack,你可能要閱讀下 Webpack 關於代碼分割的指南。你的 Webpack 配置應該相似於此。 當使用 Babel 時,你要確保 Babel 可以解析動態 import 語法而不是將其進行轉換。對於這一要求你須要 babel-plugin-syntax-dynamic-import 插件。服務器
注意: React.lazy 和 Suspense 技術還不支持服務端渲染。若是你想要在使用服務端渲染的應用中使用,咱們推薦 Loadable Components 這個庫。它有一個很棒的服務端渲染打包指南。babel
React.lazy 函數能讓你像渲染常規組件同樣處理動態引入(的組件)。網絡
const OtherComponent = React.lazy(() => import('./OtherComponent'));
function MyComponent() {
return (
<div> <OtherComponent /> </div>
);
}
複製代碼
這個函數他返回了一個Promise,須要用函數去調用,並且仍是主動拋錯的,resolvereact-router
const OtherComponent = React.lazy(() => import('./OtherComponent'));
const TowComponent = React.lazy(() => import('./TowComponent'))
function MyComponent() {
return (
<Suspense fallback={<div>Loading...</div>}> <OtherComponent /> <TowComponent /> </Suspense>
);
}
複製代碼
那麼 咱們繼續問題,懶加載的組件,在加載的過程當中遇到一個問題如(網絡問題)咱們該怎麼樣來維護用戶體驗呢?——不至於讓用戶看到空白 它會觸發一個錯誤。你能夠經過異常捕獲邊界**(Error boundaries)**dom
注意 錯誤邊界僅能夠捕獲其子組件的錯誤,它沒法捕獲其自身的錯誤。若是一個錯誤邊界沒法渲染錯誤信息,則錯誤會冒泡至最近的上層錯誤邊界,這也相似於 JavaScript 中 catch {} 的工做機制。異步
仍是上面代碼:函數
import MyErrorBoundary from './MyErrorBoundary';
const OtherComponent = React.lazy(() => import('./OtherComponent'));
const TowComponent = React.lazy(() => import('./TowComponent'))
function MyComponent() {
return (
<MyErrorBoundary>
<Suspense fallback={<div>Loading...</div>}>
<OtherComponent />
<TowComponent />
</Suspense>
<MyErrorBoundary>
);
}
複製代碼
MyErrorBoundary 以下【選自官方文檔】this
class MyErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// 更新 state 使下一次渲染可以顯示降級後的 UI
return { hasError: true };
}
componentDidCatch(error, info) {
// 你一樣能夠將錯誤日誌上報給服務器
logErrorToMyService(error, info);
}
render() {
if (this.state.hasError) {
// 你能夠自定義降級後的 UI 並渲染
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
export default MyErrorBoundary ;
複製代碼
好讓咱們回來 在SPA 單頁面程序中,咱們可能要在多個頁面中用到組件的懶加載,這樣的話咱們就能夠吧他定義在路由中 很簡單 套進去就能夠了spa
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>
);
複製代碼
接下來咱們就會想了,既然是import
那是否是也能夠嚮導入組件那種 進行 重命名
錯誤示範
const Tow = React.lazy(() => import('./TowComponent'))
複製代碼
注意:不能夠直接這樣子作 ,eact.lazy 目前只支持默認導出(default exports)。若是你想被引入的模塊使用命名導出(named exports),你能夠建立一箇中間模塊,來從新導出爲默認模塊。這能保證 tree shaking 不會出錯,而且沒必要引入不須要的組件。
// ManyComponents.js
export const MyComponent = /* ... */;
export const MyUnusedComponent = /* ... */;
複製代碼
// MyComponent.js
export { MyComponent as default } from "./ManyComponents.js";
複製代碼
// MyApp.js
import React, { lazy } from 'react';
const MyComponent = lazy(() => import("./MyComponent.js"));
複製代碼
可是 真的有必要這樣子作嗎?