[譯]React高級指引2:代碼分割

原文連接:reactjs.org/docs/code-s…html

打包

大多數React應用都會使用WebpackRollupBrowserify來打包代碼文件。打包是一個引入文件並把它們合併到一個文件的過程,最終造成一個bundle。這個bundle能夠在網頁上被加載一整個應用。react

例子 App:webpack

// app.js
import { add } from './math.js';

console.log(add(16, 26)); // 42
複製代碼
// math.js
export function add(a, b) {
  return a + b;
}
複製代碼

Bundle:git

function add(a, b) {
  return a + b;
}

console.log(add(16, 26)); // 42
複製代碼

注意: 你打包的bundle最終與上面的例子有很大的不一樣。github

若是你使用Create React AppNext,jsGatsby或其餘相似的工具,那麼你能夠使用內置的Webpack來打包你的應用。web

若是不是,那麼你須要自行安裝打包工具。好比你能夠在Webpack網站查看安裝使用教程。bash

代碼分割

打包是個很是棒的技術,可是當你的應用逐漸擴大時,你最終生成的代碼包也會隨之變大,尤爲是當你使用了龐大的第三方庫時。爲了不你的應用須要長時間地加載,請時刻注意須要包含在代碼包內的代碼,以避免它變得很大。babel

爲了不生成體積巨大的代碼包,咱們須要一開始就分割它們。代碼分割是WebpackRollup和Browserify(經過factor-bundle)這類打包器支持的特性,它們能夠構建多個代碼包並在運行時動態地加載它們。網絡

代碼分割你的應用可讓你「懶加載」當前用戶須要的部分,使你的應用性能大幅度提升。在沒有減小代碼量的前提下,你能夠避免加載用戶不會用到的代碼,減小初始化時加載的代碼量。react-router

import()

在應用中引進代碼分割的最好方式是經過動態import()語法。

以前

import { add } from './math';

console.log(add(16, 26));
複製代碼

以後

import("./math").then(math => {
  console.log(math.add(16, 26));
});
複製代碼

注意: 動態import()語法只是ECMAScript (JavaScript) 的提案,目前還不是標準語法。可是在最近的版本中它將會被引進。

當Webpack在打包時遇到了此類語法,它就會自動地進行代碼分割。若是你使用的是Create React App,建立的工程已經爲你配置好相關功能,能夠直接使用該特性Next,js也支持該特性不須要再進行配置。

若是你自行配置Webpack,那麼你可能須要查閱Webpack代碼分割指導。你的Webpack配置應該相似這種

若是使用Babel,你須要確保Babel可以解析動態import語法而不是轉換它。能夠經過babel-plugin-syntax-dynamic-import.瞭解相關知識。

React.lazy

注意: React.lazy和Suspense技術目前還不支持服務端渲染。若是你想要對在服務端渲染的應用進行代碼分割,咱們推薦使用Loadable Components。它有一個很棒的服務端渲染打包指南

React.lazy功能讓你把動態import做爲常規組件渲染。

以前

import OtherComponent from './OtherComponent';
複製代碼

以後

const OtherComponent = React.lazy(() => import('./OtherComponent'));
複製代碼

OtherComponent組件第一次被渲染時,包含這個組件的代碼包會被自動加載。

React.lazy接收一個函數做爲參數,這個函數調用動態import()。他必須返回一個Promise對象resolve包含了React組件的default export模塊。

這個懶加載組件以後應該在Suspense組件中渲染,這個組件可以在咱們等待懶加載組件加載時展現一些後備內容(如加載圖標)

const OtherComponent = React.lazy(() => import('./OtherComponent'));

function MyComponent() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <OtherComponent />
      </Suspense>
    </div>
  );
}
複製代碼

fallback屬性接收任何你想要在等待組件加載時渲染的React元素。你能夠把Suspense組件放在懶加載組件層級之上的任意位置。你也能夠把多個懶加載組件做爲Suspense組件的子元素。

const OtherComponent = React.lazy(() => import('./OtherComponent'));
const AnotherComponent = React.lazy(() => import('./AnotherComponent'));

function MyComponent() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <section>
          <OtherComponent />
          <AnotherComponent />
        </section>
      </Suspense>
    </div>
  );
}
複製代碼

異常捕獲邊界(Error boundaries)

若是模塊加載失敗(好比由於網絡請求失敗致使),這會致使錯誤。你能夠經過異常捕獲邊界來處理和修復這些異常來給用戶一個良好的用戶體驗。一旦建立了異常捕獲邊界,你就能夠在發生網絡異常時經過在懶加載組件層級之上使用它來展現錯誤狀態。

import MyErrorBoundary from './MyErrorBoundary';
const OtherComponent = React.lazy(() => import('./OtherComponent'));
const AnotherComponent = React.lazy(() => import('./AnotherComponent'));

const MyComponent = () => (
  <div>
    <MyErrorBoundary>
      <Suspense fallback={<div>Loading...</div>}>
        <section>
          <OtherComponent />
          <AnotherComponent />
        </section>
      </Suspense>
    </MyErrorBoundary>
  </div>
);
複製代碼

基於路由的代碼分割

在哪裏引入代碼分割是一個讓人頭疼的事情。你首先要確保你選擇的地方可以均勻地分割代碼包,此外還要保證這樣作不會影響用戶體驗。

一個好的選擇是在路由中使用它。大部分人都習慣在網頁跳轉時加載切換過程。因此你能夠在這個時候須要從新渲染整個頁面,這樣用戶就不用再切換頁面的同時再與其餘元素交互了。

下面的例子講述瞭如何使用React RouterReact.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>
);
複製代碼

命名導出(Named Exports)

React.lazy目前只支持default export。若是你想要引入的模塊使用的是命名導出,那麼你能夠建立一個新的模塊做爲媒介來從新default export。這能保證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"));
複製代碼
相關文章
相關標籤/搜索