1. 程式人生 > >React 按需加載 - 代碼分隔

React 按需加載 - 代碼分隔

ports 支持 mis scrip nor mic ... 服務端 不能

代碼分隔

我們現在大多數React項目都是以Webpack 或者 Browserify等將一堆的jsx文件組織一起,並且由一個類似index.js的入口文件串聯起來的單頁面web頁面。

例如:


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

App:


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

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

打完包後:


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

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

從這個例子可以看出,打完包後將所有的js都壓縮到一個文件裏了。隨著項目越來越大,打包的文件也會越來越大,如果再引入一些第三方的js庫,那就更龐大了。

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

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

這麽做,即使沒有減少整個項目的代碼量,也會避免在項目初始加載時,加載沒必須的js,從而使用項目性能有所提升。

import()

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

使用 動態 import 之前:


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 手稿》

React 按需加載 - 代碼分隔