React.lazy を安心して使用する方法: 高速なイテレーション中にコンポーネントを安全に読み込む
React.lazy は、オンデマンドでコンポーネントを読み込み、アプリのパフォーマンスを向上させるための素晴らしい方法です。しかし、時には "ChunkLoadError" や "Loading chunk failed" といった問題が発生することがあります。
ジレンマ
最近のソフトウェア開発は、「早く進めて物を壊す」という流行の哲学のもとで、ますます速く動いています。ここでの判断はありません—ただ、そういう状況であるということです。ただし、この速いペースが時々問題を引き起こすことがあります。特に、React のコンポーネントを読み込む際にです。
もし React.lazy を使ってコンポーネントをオンデマンドで読み込むプロジェクトに取り組んでいる場合、ChunkLoadError
や Loading chunk failed
といった問題に直面したことがあるかもしれません。これにはいくつかの理由が考えられます:
- ネットワークに問題がある、たとえば、ユーザーのインターネット接続が遅い、または不安定である。
- ユーザーが古いバージョンのアプリを使用しており、ブラウザが存在しないチャンクを読み込もうとしている。
通常、ページを再読み込みすることで問題は解決しますが、ユーザー体験としては良くありません。ユーザーが他のルートに移動しているときにホワイトスクリーンが表示されたらどうでしょうか—アプリの印象としては良くありません。
速度を求める一方でスムーズなユーザー体験を提供することができるのでしょうか?もちろんです。ここでその方法を紹介します(もちろん TypeScript を使います)。
解決策
力技的な解決策として、異なるバージョンのすべてのチャンクをサーバーに保存するというものがあります。こうすれば「チャンクが見つからない」問題はなくなります。しかし、アプリが成長するとディスクスペースの要求が増え、この解決策は実現不可能になるかもしれません。また、ネットワークの問題も解決されません。
リトライやリフレッシュが問題を解決できる以上、これらのソリューションをコードに組み込むことが できます。問題は通常、ユーザーが別のルートに移動する際に起こるため、ユーザーに気づかれずに解決できる場合があります。必要なのは、リトライやリフレッシュを処理する React.lazy
関数をラップすることだけです。
この種のソリューションの実装方法については既に素晴らしい記事が存在しているため、ここではソリューションのアイデアと内部構造に焦点を当てます。
ラッパーを作成する
最初のステップは React.lazy
関数をラップすることです:
リトライを処理する
ネットワークの問題に対しては、importFunction
を tryImport
関数でラップしてリトライを処理します:
シンプルですね?リトライをより効率的に行うために、エクスポネンシャルバックオフ アルゴリズムも実装できます。
リフレッシュを処理する
古いバージョンの問題に対しては、エラーをキャッチしてページをリフレッシュすることで対処できます:
ただし、この実装は非常に危険で、リフレッシュで解決できないエラーが発生すると無限ループに入る可能性があります。同時に、アプリの状態はリフレッシュ時に失われます。そこで、sessionStorage
の助けを借りて、ページをリフレッシュしようとしたことを保存します:
これで、safeLazy
関数からエラーをキャッチした場合、それがリフレッシュでは解決できない問題であることが分かります。
同一ページに複数の lazy コンポーネントがある場合
現在の実装には隠れた落とし穴があります。同じページに複数の lazy コンポーネントがある場合、他のコンポーネントが sessionStorage
の値をリセットしてしまい、無限リフレッシュループが発生する可能性があります。この問題を解決するために、コンポーネントごとに一意のキーを使用します:
これで、各コンポーネントが独自の sessionStorage
キーを持つようになり、無限リフレッシュループが防止されます。このソリューションをさらに細かく見直しても良いでしょう。たとえば:
- すべてのキーを配列に集め、1つのストレージキーだけにする。
- エラースロー前にページを1回以上リフレッシュするリフレッシュリミットを設定する。
しかし、基本的なアイデアは伝わったかと思います。テストおよび設定が施された包括的な TypeScript ソリューションは、GitHub リポジトリ で利用可能です。また、react-safe-lazy
パッケージは NPMで公開されているので、すぐにプロジェクトで使用できます。
結論
ソフトウェア開発は繊細な作業であり、最も小さな詳細でさえ解決に努力が必要です。この記事が React.lazy
の問題を優雅に解決し、あなたのアプリのユーザー体験を向上させる手助けになれば幸いです。