使用 React.Suspense 替換 react-loadable

引言

當前大部分 React 應用需要使用 code splitting 的時候,都選擇使用優秀的 react-loadable 來處理檢測代碼段是否已加載。然而,隨着React v16.6 的發佈,我們有一個非常難得的機會 ,可以刪除我們的第三方依賴!

React.Suspense是一個新添加到核心React庫中的功能,t他的功能基本和 react-loadable 一致,所以不用多說,讓我們來看看用 React.Suspense 替換 react-loadable

首先是 code splitting(代碼分割)

如果你不太熟悉這個功能,webpack 基本上可以幫助你把代碼打包成多個chunk,當用戶打開你的應用的時候,先會下載一個主bundle,然後當用戶導航到一些頁面包含了其他的邏輯和靜態資源的使用,再按需加載這些chunk。但是要手動處理成這個效果非常的複雜,當然這樣處理後可以很有效地減少用戶的白屏時間,並且讓移動端用戶有更好的體驗。webpack(或者其他解決方案)在這裏扮演了一個很重要的角色,他可以在創建這些bundle的時候處理這些複雜的邏輯,並且在需要的時候再去下載他們。所以我們所需要做的就是將該功能合併到我們的應用程序中,這樣用戶就可以獲得無縫的體驗。

Step 1: 升級到 React 16.6

對於 v16 的用戶來說,可以直接升級到 16.6,但是對於v15的用戶來說,請按照官方遷移說明來升級。

Step 2: 確定您的異步組件

在 react-loadable 當中,按需加載可能在長這樣:

const Loading = ({ pastDelay }) => {
  if (pastDelay) {
    return <Spinner />;
  }
  return null;
};
 
export const johanAsyncComponent = Loadable({
  loader: () => import(/* webpackChunkName: "johanComponent" */ './johan.component'),
  loading: Loading,
  delay: 200
});

在上面的代碼中,我們做了幾個事情:

  1. 我們定義一個 Loading 組件,用於在請求組件的時間和加載組件以及準備渲染之間顯示。
  2. johanAsyncComponent 中的loading參數是在請求/響應週期中顯示的組件,這裏我們定義了一個 自定義Loading組件
  3. 設置了一個delay,我們只在加載超過 200 毫秒的時候顯示Spinner ,這樣做可以很好地避免在請求快速完成時“閃爍”加載中的組件。

Step 3:轉換到 React.Suspense

使用 React.Suspense 顯然代碼更爲優雅。

const johanComponent = React.lazy(() => import(/* webpackChunkName: "johanComponent" */ './myAwesome.component'));
 
export const johanAsyncComponent = props => (
  <React.Suspense fallback={<Spinner />}>
    <johanComponent {...props} />
  </React.Suspense>
);
  1. 我們使用React.lazy封裝動態import,類似於第一個示例中的’loading’參數。
  2. 我們定義一個React.Suspense組件,其中包含一組fallback JSX,以便在我們等待異步加載時進行渲染。 通常,這將是一個微調器或其他等待指示器。
  3. 我們定義了一些 children 的 JSX,這些都是使用 React.lazy 包含的組件。

ok, 到此,其實我們已經實現了和 react-loadable 一樣的功能。或許細心的你可能發現了,React.Suspense 沒有 delay 參數。是的, React.Suspense 沒有在內置支持 delay 功能,因此,即使加載工程只需要幾毫秒的時間, fallback也會被執行,就上述代碼來說,也就是 Spinner 會閃爍一下,如果資源被加載得非常快得話。就目前而言,我們需要自己在 fallback 得組件中自行處理這些邏輯,例如在 componentDidMount 中設置一個定時器,使其直到將來的某個時間才呈現。

Step 4:加載出錯的處理

該如何處理如果出現chunk加載失敗的情況呢?

react-loadable

優秀的庫當然有內置的方法支持處理加載失敗的情況

const Loading = (props) => {
  if (props.error) {
    return <p>Error!</p>;
  } else if (props.pastDelay) {
    return <p>Loading...</p>;
  } else {
    return null;
  }
}

Suspense

在 React 16 當中有一個新的功能Error Boundary,這只是一個可感知錯誤的組件,它能夠從其children中捕獲和處理錯誤。爲了處理異步加載的問題,我們可以簡單地定義一個自定義的ErrorEdge組件,並將異步組件的使用包裝在其中。

<MyCustomErrorBoundary>
  <MyAwesomeAsyncComponent />
</MyCustomErrorBoundary>

最後一步

npm uninstall react-loadable

替換有什麼好處?

顯然,當我們考慮升級或重構時,我們總是用“它以目前的方式工作得很好”爲藉口推脫。那麼,這是否值得升級?

更小的bundle: react-loadable gzip後大概是 2K,去掉這個第三方庫後,所以打包時間並沒有減少多少,但是確確實實減少了2K。

增加可維護性:使用 React 的核心庫,總比第三方庫更容易維護。

總結

總的來說,我不敢說這是一個必須替換的功能,但是考慮到衆多的因素,他們兩個的功能基本是相同的,而且代碼修改也相對比較簡單,並不需要做很大的改動,所以建議使用這個新特性來做按需加載。

原文鏈接:https://objectpartners.com/2018/12/05/migrate-from-react-loadable-to-react-suspense/
原文作者:Mike Plummer

譯文地址:https://cloud.tencent.com/developer/article/1381296
譯文作者:志航

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章