繁體中文(香港)
  • react
  • lazy
  • suspense

自信使用 React.lazy:當快速迭代時安全加載組件的方法

React.lazy 是一種根據需要加載組件並提高應用性能的絕佳方式。然而,有時它可能會導致一些問題,例如「ChunkLoadError」和「加載塊失敗」。

Gao
Gao
Founder

困境

如今,軟體開發在流行的「快速行動並打破常規」的哲學下更快地推進。在這裡不做評價——事情就是這樣。然而,這種快節奏有時會導致問題,特別是在用 React 加載組件時。

如果你正在一個使用 React.lazy 來根據需要加載組件的專案,你可能遇到過像 ChunkLoadError 和「加載塊失敗」這樣的問題。以下是一些可能的原因:

  • 存在網絡問題,例如,用戶的互聯網連接緩慢或不穩定。
  • 用戶的應用版本過時,瀏覽器正在嘗試加載已經不存在的塊。

通常,簡單刷新頁面可以解決問題,但這對用戶來說不是最佳體驗。想像一下,當用戶導航到另一個路由時出現白屏——這對你的應用來說不好看。

我們能在速度需求與流暢用戶體驗之間取得平衡嗎?當然。讓我告訴你方法(當然是用 TypeScript)。

解決方案

一個粗暴的解決方案是將所有版本的塊保存在服務器中,這樣就不會出現「缺失塊」問題。隨著應用的增長,這種解決方案可能因磁碟空間需求增加而變得不可行,並且它仍然無法解決網絡問題。

鑑於重試或刷新可以解決問題,我們可以在代碼中實施這些解決方案。鑒於問題通常發生在用戶導航至另一個路由時,我們甚至可以在用戶不注意的情況下解決它。我們所需要做的只是構建一個包裹函數來包裹 React.lazy,以便處理重試和刷新。

已經有一些很好的文章介紹如何實現這種解決方案,因此我將重點放在該解決方案的思路和內部運作上。

創建包裹函數

第一步是創建一個包裹 React.lazy 函數的包裹函數:

處理重試

對於網絡問題,我們可以通過將 importFunction 包裹在 tryImport 函數中來處理重試:

看起來很簡單吧?你還可以實現 指數退避 演算法來更有效地處理重試。

處理刷新

對於過時版本問題,我們可以通過捕捉錯誤並刷新頁面來處理刷新:

然而,這種實現非常危險,因為當錯誤無法通過刷新解決時可能導致無限刷新循環。同時,應用狀態將在刷新過程中丟失。因此我們需要 sessionStorage 的幫助來存儲我們已經嘗試刷新頁面的消息:

現在,當我們從 safeLazy 函數中捕捉錯誤時,我們知道這是一些刷新無法解決的問題。

同一頁面上的多個懶加載組件

目前的實現中仍有一個潛在的陷阱。如果你在同一頁面上有多個懶加載組件,無限刷新循環仍可能發生,因為其他組件可能會重置 sessionStorage 值。為了解決這個問題,我們可以為每個組件使用一個唯一鍵:

現在,每個組件都將擁有自己的 sessionStorage 密鑰,將避免無限刷新循環。我們可以繼續苛求解決方案,例如:

  • 將所有鍵集中在一個數組中,因此只需一個存儲鍵。
  • 設置刷新限制以便在拋出錯誤前重複刷新頁面多次。

但我認為你明白這個想法。一個完整的 TypeScript 解決方案以及測試和配置可在 GitHub 儲存庫 中找到。我還在 NPM 上發佈了 react-safe-lazy 包,所以你可以立即在你的專案中使用它。

結論

軟體開發是一項細緻的工作,即便是最小的細節也可能需要努力去解決。我希望這篇文章能幫助你優雅地處理 React.lazy 的問題,並改善你的應用的用戶體驗。