React提供了lazy與Suspense改善程式碼分割的方式讓專案能夠決定是否需要載入,但是可能有些人發現到討論度相較其他功能來得低不少,這邊將會介紹功能與討論實用性的問題。

React lazy與React suspense的出現

可參考官方網站的code-splitting文章
當我們在開發程式的時候,我們希望避免引入多過的程式碼或是開發套件,所以React提供了一些方法來讓開發者可以進行程式碼分割。

使用介紹

假設你有一個Component叫Form

1
import Form from './Form';

React lazy使用的時候,需要搭配import使用,裡面回傳的型別是一個Promise。

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

再來使用Suspense包裹lazy component,裡面可以放置多個。
在載入的過程中,會顯示fallback內的內容,這裡用文字loading表示,可以替換成其他內容,例如:載入中的圖片。

1
2
3
4
5
6
7
8
9
10
11
12
13
import React, { Suspense } from 'react';

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

const FormPage = () => {
return (
<div>
<Suspense fallback={<p>>Loading...</p>}>
<Form />
</Suspense>
</div>
);
}

以Promise使用React lazy

1
2
3
4
5
6
7
8
9
10
11
function App() {
return (
<div className="App">
<h2>Lazy loading made simple in React</h2>

<Suspense fallback={<Loading />}>
<LazyUser name="sara" />
</Suspense>
</div>
);
}

應用在Route上

如果在每個component上面寫lazy,想必是一件很複雜的工程,因此為了簡單化流程,可以寫在控管Route的元件上面。
這邊拿React官方的範例上來,你會發現管理起來也相對方便很多:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import React, { Suspense, lazy } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';

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

以Promise模擬情境

這邊寫了一段簡易的程式用來模擬loading的情境,有興趣的話可以研究看看:

討論實用性

你會發現,其實React lazy與Suspense提供了不錯的解決方案在某些情境上面,但是為什麼卻很少被拿來討論呢?
以下做一些整理:

  1. 不支援server-side rendering
    React官方的描述:
    React.lazy and Suspense is not yet available for server-side rendering. If you want to do code-splitting in a server rendered app, we recommend Loadable Components. It has a nice guide for bundle splitting with server-side rendering.
    很多網站都有做SSR的需求,光是這點就讓很多專案不選擇使用它了。

  2. 更好的方法
    React官方的描述:
    Code splitting is one of the most compelling features of webpack. This feature allows you to split your code into various bundles which can then be loaded on demand or in parallel.
    當我們要打包程式碼的時候,我們會用到一些打包工具,例如:webpack,像是webpack就有很多相關的套件可以載入使用,每個套件都有提供個別的解決方案應用在專案上。

  3. 開發成本的考量
    時間是最貴的開發成本,如果需要寫很多程式去控制哪些程式在什麼狀況下才需要被載入,可能會浪費很多開發時間在上面,也許用其他套件不會是最佳解,但是相較之下的成本考量反而會是更好的選擇。
    開發很重要的一點是,優化是一定對專案有幫助的,但是如果這個優化犧牲了很大的成本只換來一點皮毛的改善,那麼你可能會選擇做其他開發的工作。

  4. 內建的bundle
    如果你當初啟用你的專案是Create React App、Next.js…這種的套件產生你的專案,他們自己有內建webpack提供打包。