[譯] 延遲載入 React Components (用 react.lazy 和 suspense)

江米小棗tonylua發表於2019-02-18

原文: blog.bitsrc.io/lazy-loadin…

雖然在 React 16.8.1 中終於面世的 hooks 引人矚目,但在去年釋出的 16.6.0 版本里也包含了一個吸引人的新特性,可以讓我們在不依賴第三方庫的情況下簡化對延遲載入(lazy loading)的處理。

讓我們看看如何藉助這個特性改善應用效能,並構建更好的使用者體驗。

按照過往的經驗,在構建元件的時候,將其用類似 Bit 的工具歸納起來是很有用的 -- 可以分享你的元件並在任意應用中使用之,以加速開發並保持 DRY 原則。

React.lazy() 是什麼?

這項新功能使得可以不借助任何附加庫就能通過程式碼分割(code splitting)延遲載入 react 元件。延遲載入是一種優先渲染必須或重要的使用者介面專案,而將不重要的專案悄然載入的技術。這項技術已經被完全整合進了 react 自身的核心庫中。之前我們要用 react-loadable 達到這一目的,但現在用 react.lazy() 就行了。

Suspense 掛起元件

Suspense 是一個延遲函式所必須的元件,通常用來包裹住延遲載入元件。多個延遲載入的元件可被包在一個 suspense 元件中。它也提供了一個 fallback 屬性,用來在元件的延遲載入過程中顯式某些 react 元素。

延遲和掛起為何重要?

首先,打包工具將所有程式碼元件相繼歸納到一個 javascript 塊中,並將其傳遞給瀏覽器;但隨著應用增長,我們注意到打包的體積也與日俱增。這會導致應用因為載入慢而難以使用。藉助程式碼分割,程式碼包能被分割成更小的塊,最重要的塊先被載入,而其餘次要的則延遲載入。

同時,我們知道構建應用的一個最佳實踐是:應該考慮到使用者在使用移動網際網路資料和其他慢速網路連線時的情況。作為開發者就應該在哪怕是在資源讀取到 DOM 中的掛起階段也能控制好使用者體驗。

起步

根據 react 官方文件,如果使用了下列技術,那麼就已經有 webpack 打包配置了:

  • CRA (create react app)
  • Next js
  • Gatsby

如果沒有的話,就需要自己設定打包了。比如,讀一下 Webpack 官方文件中的 InstallationGetting Started

Demo

我們用 create-react-app 建立一個 react 應用,並在裡面實現帶掛起的延遲載入,它將用來顯示 MTV Base 上 2019 上頭牌藝人的專輯名和專輯數量。我用 create-react-app 建立了一個乾淨的應用,幷包含了一個我們可以在本例中用得上的簡易元件。

  • 克隆 gitlab.com/viclotana/r…
  • 解壓檔案並開啟一個終端視窗
  • 在解壓出的檔案的根目錄下安裝專案的 node modules 依賴
  • 用以下命令啟動開發伺服器:
$ sudo npm start
複製程式碼

Sample Application

就是這麼個簡單的應用,藝人的資料被從應用中的一個 store 中讀出。當然你也可以自己編寫這些程式碼,應用的 src 下面應該有這些檔案:

  1. Artists.js
import React from ‘react’;
import ‘./App.css’;
import artists from “./store”;
export default function Artists(){
 return (
   <>
   <h1>MTV Base Headline Artists 2019</h1>
   {artists.map(artist =>(
   <div id=”card-body” key={artist.id}>
    <div className=”card”>
     <h2>{artist.name}</h2>
     <p>genre: {artist.genre}</p>
     <p>Albums released: {artist.albums}</p>
    </div>
   </div>
    ))}
   </>
);
}
複製程式碼
  1. Store.js
export default [
{
  id: “1”,
  name: “Davido”,
  country: “Nigeria”,
  genre: “Afro-Pop”,
  albums: “2”
},
{
  id: “2”,
  name: “AKA”,
  country: “South-Africa”,
  genre: “Hip-Hop”,
  albums: “4”
},
{
  id: “3”,
  name: “Seyi Shay”,
  country: “Nigeria”,
  genre: “R&B”,
  albums: “2”
},
{
  id: “4”,
  name: “Sauti Sol”,
  country: “Kenya”,
  genre: “Soul”,
  albums: “3”
}
];
複製程式碼
  1. Index.js
import React from ‘react’;
import ReactDOM from ‘react-dom’;
import ‘./index.css’;
import Artists from ‘./Artists’;
class App extends React.Component {
 render(){
  return(
   <div className=”App”>
    <Artists />
   </div>
   );
 }
}
ReactDOM.render(<App />, document.getElementById(‘root’));
複製程式碼
  1. App.css
.App {
 text-align: center;
}
h1 {
 padding: 30px;
}
#card-body {
 display: inline-flex;
 padding: 10px;
 margin: 30px 30px;
 border: 5px solid rgb(93, 171, 207);
 border-radius: 8px;
 background: lightblue;
}
複製程式碼

現在讓我們看看如何用 react.lazy 及 suspense 去處理藝人元件的延遲載入。

  • index.js 的頭部引入 react 中的 lazy 和 suspense:
import { Suspense, lazy } from 'react';
複製程式碼
  • 要像常規元件一樣渲染一個動態引入的元件,使用 react 文件中提供的 react.lazy 函式語法,如下:
const OtherComponent = React.lazy(() => import('./OtherComponent'));

function MyComponent() {
  return (
    <div>
      <OtherComponent />
    </div>
  );
}
複製程式碼
  • 應用到我們的藝人元件上:
const Artists = React.lazy(() => import('./Artists'));

function MyComponent() {
  return (
    <div>
      <Artists />
    </div>
  );
}
複製程式碼

若在 App 元件渲染期間,包含藝人元件的模組沒有載入完,就必須顯示一些提示等待的 fallback 內容 -- 比如一個載入指示器,下面是用 Suspense 元件完成這一目的的語法:

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

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

應用到藝人元件上:

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

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

把以上拼在一起, index.js 看起來是這樣的:

import React, { lazy, Suspense } from ‘react’;
import ReactDOM from ‘react-dom’;
import ‘./index.css’;
// import Artists from ‘./Artists’;
const Artists = lazy(() => import(‘./Artists’))
class App extends React.Component {
 render(){
  return(
   <div className=”App”>
    <Suspense fallback={<h1>Still Loading…</h1>}>
     <Artists />
    </Suspense>
   </div>
  );
 }
}
ReactDOM.render(<App />, document.getElementById(‘root’));
複製程式碼

在你的 localhost 上應該執行的很快,以至於你根本感覺不到有什麼改變。但你可以建立一段時間統計程式碼,或模擬慢速網路:

  • 開啟瀏覽器的 dev tools
  • 選擇 network tab
  • 點選右側遠端的 online tab,顯示其他選項(最右側的下箭頭)
  • 選擇 fast 3G

[譯] 延遲載入 React Components (用 react.lazy 和 suspense)

現在重新整理瀏覽器就能看到延遲載入如何發生了...

Still Loading…

多個延遲載入元件

那麼再快速新增一個渲染標題的小元件,看看 react.lazy 如何仍只用一個 suspense 元件處理:

建立 performers.js 檔案:

mport React from ‘react’;
import ‘./App.css’;
export default function Performers(){
 return (
  <>
  <h2>These are the MTV Base Headline Artists...</h2>
  </>
 );
}
複製程式碼

並在 index.js 中新增一行延遲載入程式碼:

import React, { lazy, Suspense } from ‘react’;
import ReactDOM from ‘react-dom’;
import ‘./index.css’;
const Artists = lazy(() => import(‘./Artists’))
const Performers = lazy(() => import(‘./Performers’))
class App extends React.Component {
 render(){
  return(
   <div className=”App”>
    <Suspense fallback={<h1>Still Loading…</h1>}>
     <Artists />
     <Performers />
    </Suspense>
   </div>
  );
 }
}
ReactDOM.render(<App />, document.getElementById(‘root’));
複製程式碼

現在,在 suspense 中的佔位符元素渲染之後,兩個延遲載入的元件便立刻顯示出來了。

The two lazy components loaded within one suspense

這和 loadable 中必須為每個延遲載入元件都弄個 loading 是不同的。

⚠️ 重要提示

React.lazy 和 Suspense 在服務端渲染中尚不可用。如果想在伺服器渲染的應用中使用程式碼分割,Loadable 元件仍是強烈推薦的,在其文件中有很好相關解釋。

總結

我們看到了如何用 react 提供的 lazy 和 suspense 元件實現延遲載入。和這個新特性帶來的眾多可能性相比,以上例子過於基礎。你可以在自己的專案中靈活應用,編碼愉快!



--End--

[譯] 延遲載入 React Components (用 react.lazy 和 suspense)

搜尋 fewelife 關注公眾號

轉載請註明出處

相關文章