32
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

お題は不問!Qiita Engineer Festa 2023で記事投稿!

SuspenseとReact.lazyを使いパフォーマンス最適化

Last updated at Posted at 2023-06-29

はじめに

最近、WEBサイトのパフォーマンス最適化に興味があって、ChatGPTにパフォーマンス向上の方法を聞いてみました。
chatGPT.png
なるほど~
イメージの最適化と、コード分割が手軽にはじめられそうな気がします(個人の主観です)
ということで、パフォーマンス向上のために、コード分割をする方法について紹介していきます。

コード分割

コード分割をすると、ユーザーが必要としないコードを読み込まなくて済むため、初期ロードの際に読む込むコード量を削減できます。

コード分割の方法

1. import()

Before
import { add } from './math';

console.log(add(16, 26));
After
import("./math").then(math => {
  console.log(math.add(16, 26));
});

2. React.lazy

Before
import OtherComponent from './OtherComponent';
After
const OtherComponent = React.lazy(() => import('./OtherComponent'));

このコンポーネントがはじめてレンダーされる時、OtherComponentを含むバンドルを自動的にロードしてくれます。

2つの方法の主な違い

  • ダイナミックインポートを直接使用するやり方
    • モジュールの関数が直接呼び出されます。
  • React.lazyを使用するやり方
    • ダイナミックインポートはReact.lazyによって間接的に使用され、ロードされたモジュールはReactコンポーネントとしてレンダリングされます。

なお、React.lazyを使った場合、Suspenseコンポーネントを使って、非同期にロードされるコンポーネントのローディング状態を制御することができます。
次の章では、Suspenseについて説明していきます。

Suspenseとは何か

Suspenseの概要

ReactSuspenseを使うことで、コンポーネント内で非同期な操作(たとえば、データの取得やコードの分割)が行われる場合に、ローディング状態を管理することが可能になります。
Suspenseコンポーネントの主な目的は、非同期な操作が完了するまでの間、特定のコンテンツ(通常はコンポーネント)を遅延させることです。

フォールバックUIとの連携

fallbackプロパティを使用してフォールバックUIを指定することができます。
フォールバックUIは、非同期な操作がまだ完了していない間に表示される、ローディングスピナーやローディングメッセージなどのコンポーネントのことです。ユーザーに操作の進行状況を伝え、待機中であることを明示する役割を果たします。

React.lazyとSuspenseを組み合わせたコードスプリッティングの実装

実際のコードスプリッティングの例

MyComponent.jsx
import React from 'react';

const MyComponent = () => {
  return <div>My Component</div>;
};

export default MyComponent;
App.jsx
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)の利用

SuspenseReact.lazyを使ったコードスプリッティングでは、エラーハンドリングは非常に重要な役割を果たします。特に、動的にロードされるコンポーネントがエラーを吐いた場合や、ネットワークエラーなどによりコンポーネントのロードが失敗した場合には、適切なエラーハンドリングが必要となります。

今回は、エラーハンドリングの手法としてエラーバウンダリーを紹介します。エラーバウンダリーは、子コンポーネントツリーで発生するエラーをキャッチし、それらをログに記録し、崩壊したコンポーネントツリーの代わりにフォールバックUIを表示する役割を果たします。

ErrorBoundary.jsx
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;
App.jsx
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を使いパフォーマンス最適化」という記事を書きました。簡単に導入できる手法かつ、コンポーネントそのものを汚すことはないので、参考にしてみてください。

32
18
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
32
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?