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

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

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

Gao
Gao
Founder

Stop wasting weeks on user auth
Launch secure apps faster with Logto. Integrate user auth in minutes, and focus on your core product.
Get started
Product screenshot

困境

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

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

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

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

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

解決方案

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

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

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

創建包裹函數

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

處理重試

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

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

處理刷新

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

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

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

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

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

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

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

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

結論

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