React 按需加載 - 代碼分隔

代碼分隔

咱們如今大多數React項目都是以Webpack 或者 Browserify等將一堆的jsx文件組織一塊兒,而且由一個相似index.js的入口文件串聯起來的單頁面web頁面。react

例如:git

// math.js
export function add(a, b) {
  return a + b;
}

App:github

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

console.log(add(16, 26)); // 42

打完包後:web

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

console.log(add(16, 26)); // 42

從這個例子能夠看出,打完包後將全部的js都壓縮到一個文件裏了。隨着項目愈來愈大,打包的文件也會愈來愈大,若是再引入一些第三方的js庫,那就更龐大了。babel

接下來介紹一下如何將React代碼分隔。(如下內容是16.6.0版本才支持的)react-router

Code Splitting會幫助你的應用實現lazy load.app

這麼作,即便沒有減小整個項目的代碼量,也會避免在項目初始加載時,加載沒必須的js,從而使用項目性能有所提高。dom

import()

最簡單直接的方式就是引入動態 import 實現代碼分隔。性能

使用 動態 import 以前:code

import { add } from './math';

console.log(add(16, 26));

使用動態 import 後:

import("./math").then(math => {
  console.log(math.add(16, 26));
});
注意,動態 import 並非標準的EcmaScript,因此須要配置 babel-plugin-syntax-dynamic-import

React.lazy

React.lazy 能夠以一個React標準組件的方法渲然一個動態引入的組件。

之前的作法:

import OtherComponent from './OtherComponent';

function MyComponent() {
  return (
    <div>
      <OtherComponent />
    </div>
  );
}

使用 React.lazy

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

function MyComponent() {
  return (
    <div>
      <OtherComponent />
    </div>
  );
}

這樣在組件MyComponent渲然的時候才加載OtherComponent

React.lazy 必須使用動態 import() 引入組件,必須返回一個 Promise Component

React.lazy 目前不支持服務端渲然

Suspense

假如在 React.lazy 時,import 失敗或者異常時,咱們須要給於提示,或者一個默認的組件,咱們就須要使用 Suspense .

例如:

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

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

fallback 也是一個組件,但不能經過 動態 import 引入的組件.

Suspense 只能包裹一個單結點,若是有多個 動態 import 的組件須要放在一個 Suspense 中時,可使用相似 React.Fragmet 包裹一下,也可使用其餘的 React 組件包裹。例如:

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>
  );
}

基於Router的代碼分隔

基於 Router 的代碼分隔,也是咱們一般所說的按需加載。是咱們推薦的方式。

例如:

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 () => {
  return(<div>I am a Lazy component</div>);
}

若是要支持命令導出,須要從新再 export ,例如:

// 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"));

推薦閱讀 《React 手稿》

相關文章
相關標籤/搜索