はじめに
最近、WEBサイトのパフォーマンス最適化に興味があって、ChatGPT
にパフォーマンス向上の方法を聞いてみました。
なるほど~
イメージの最適化と、コード分割が手軽にはじめられそうな気がします(個人の主観です)
ということで、パフォーマンス向上のために、コード分割をする方法について紹介していきます。
コード分割
コード分割をすると、ユーザーが必要としないコードを読み込まなくて済むため、初期ロードの際に読む込むコード量を削減できます。
コード分割の方法
1. import()
import { add } from './math';
console.log(add(16, 26));
import("./math").then(math => {
console.log(math.add(16, 26));
});
2. React.lazy
import OtherComponent from './OtherComponent';
const OtherComponent = React.lazy(() => import('./OtherComponent'));
このコンポーネントがはじめてレンダーされる時、OtherComponent
を含むバンドルを自動的にロードしてくれます。
2つの方法の主な違い
- ダイナミックインポートを直接使用するやり方
- モジュールの関数が直接呼び出されます。
-
React.lazy
を使用するやり方- ダイナミックインポートは
React.lazy
によって間接的に使用され、ロードされたモジュールはReactコンポーネント
としてレンダリングされます。
- ダイナミックインポートは
なお、React.lazy
を使った場合、Suspenseコンポーネント
を使って、非同期にロードされるコンポーネントのローディング状態を制御することができます。
次の章では、Suspense
について説明していきます。
Suspenseとは何か
Suspenseの概要
React
のSuspense
を使うことで、コンポーネント内で非同期な操作(たとえば、データの取得やコードの分割)が行われる場合に、ローディング状態を管理することが可能になります。
Suspense
コンポーネントの主な目的は、非同期な操作が完了するまでの間、特定のコンテンツ(通常はコンポーネント)を遅延させることです。
フォールバックUIとの連携
fallback
プロパティを使用してフォールバックUIを指定することができます。
フォールバックUIは、非同期な操作がまだ完了していない間に表示される、ローディングスピナーやローディングメッセージなどのコンポーネントのことです。ユーザーに操作の進行状況を伝え、待機中であることを明示する役割を果たします。
React.lazyとSuspenseを組み合わせたコードスプリッティングの実装
実際のコードスプリッティングの例
import React from 'react';
const MyComponent = () => {
return <div>My Component</div>;
};
export default MyComponent;
import React, { Suspense } from 'react';
const MyComponent = React.lazy(() => import('./MyComponent'));
const App = () => {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<MyComponent />
</Suspense>
</div>
);
};
export default App;
エラーハンドリングの実装
エラーバウンダリー(Error Boundaries)の利用
Suspense
とReact.lazy
を使ったコードスプリッティングでは、エラーハンドリングは非常に重要な役割を果たします。特に、動的にロードされるコンポーネントがエラーを吐いた場合や、ネットワークエラーなどによりコンポーネントのロードが失敗した場合には、適切なエラーハンドリングが必要となります。
今回は、エラーハンドリングの手法としてエラーバウンダリーを紹介します。エラーバウンダリーは、子コンポーネントツリーで発生するエラーをキャッチし、それらをログに記録し、崩壊したコンポーネントツリーの代わりにフォールバックUIを表示する役割を果たします。
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// このメソッドはエラーが発生したら、stateを更新して次のレンダリングでフォールバックUIを表示できるようにします。
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// ここでエラー情報を出力します。
console.error("An error occurred:", error, errorInfo);
// ここに適切なエラーロギングサービスへの報告コードを書くことになります。例えば、Sentry.captureException(error);
}
render() {
if (this.state.hasError) {
// エラーが発生した場合、ここでフォールバックUIを描画できます。
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
export default ErrorBoundary;
import React, { Suspense } from 'react';
import ErrorBoundary from './ErrorBoundary';
const MyComponent = React.lazy(() => import('./MyComponent'));
const App = () => {
return (
<div>
<ErrorBoundary>
<Suspense fallback={<div>Loading...</div>}>
<MyComponent />
</Suspense>
</ErrorBoundary>
</div>
);
};
export default App;
まとめ
パフォーマンス最適化への取り組みの1つの手段として、今回は、「SuspenseとReact.lazyを使いパフォーマンス最適化」という記事を書きました。簡単に導入できる手法かつ、コンポーネントそのものを汚すことはないので、参考にしてみてください。