日本語

React Suspenseで効率的なデータ取得を解き放ちましょう!コンポーネントレベルのローディングから並列データ取得まで、様々な戦略を探索し、応答性の高いユーザーフレンドリーなアプリケーションを構築します。

React Suspense:モダンアプリケーションのためのデータ取得戦略

React SuspenseはReact 16.6で導入された強力な機能で、特にデータ取得における非同期操作の処理を簡素化します。データロード中にコンポーネントのレンダリングを「一時停止」させることで、ローディング状態をより宣言的でユーザーフレンドリーに管理できます。このガイドでは、React Suspenseを使用した様々なデータ取得戦略を探り、応答性の高いパフォーマンスの高いアプリケーションを構築するための実践的な洞察を提供します。

React Suspenseの理解

具体的な戦略に入る前に、React Suspenseのコアコンセプトを理解しましょう。

Suspenseを使用したデータ取得戦略

Suspenseを使用した効果的なデータ取得戦略をいくつか紹介します。

1. コンポーネントレベルのデータ取得

これは最も直接的なアプローチであり、各コンポーネントがSuspense境界内で独自のデータを取得します。独立したデータ要件を持つシンプルなコンポーネントに適しています。

例:

ユーザーデータをAPIから取得する必要があるUserProfileコンポーネントがあるとしましょう。

// シンプルなデータ取得ユーティリティ(お好みのライブラリに置き換えてください)
const fetchData = (url) => {
  let status = 'pending';
  let result;
  let suspender = fetch(url)
    .then(res => {
      if (!res.ok) {
        throw new Error(`HTTP error! Status: ${res.status}`);
      }
      return res.json();
    })
    .then(
      res => {
        status = 'success';
        result = res;
      },
      err => {
        status = 'error';
        result = err;
      }
    );

  return {
    read() {
      if (status === 'pending') {
        throw suspender;
      } else if (status === 'error') {
        throw result;
      }
      return result;
    }
  };
};

const userResource = fetchData('/api/user/123');

function UserProfile() {
  const user = userResource.read();
  return (
    <div>
      <h2>{user.name}</h2>
      <p>Email: {user.email}</p>
    </div>
  );
}

function App() {
  return (
    <Suspense fallback={<div>ユーザーデータをロード中...</div>}>
      <UserProfile />
    </Suspense>
  );
}

説明:

利点:

欠点:

2. 並列データ取得

ウォーターフォールフェッチを回避するために、複数のデータリクエストを同時に開始し、Promise.allなどのテクニックを使用して、すべてのリクエストが完了するまで待ってからコンポーネントをレンダリングできます。これにより、全体のロード時間が短縮されます。

例:

const userResource = fetchData('/api/user/123');
const postsResource = fetchData('/api/user/123/posts');

function UserProfile() {
  const user = userResource.read();
  const posts = postsResource.read();

  return (
    <div>
      <h2>{user.name}</h2>
      <p>Email: {user.email}</p>
      <h3>投稿:</h3>
      <ul>
        {posts.map(post => (<li key={post.id}>{post.title}</li>))}
      </ul>
    </div>
  );
}

function App() {
  return (
    <Suspense fallback={<div>ユーザーデータと投稿をロード中...</div>}>
      <UserProfile />
    </Suspense>
  );
}

説明:

利点:

欠点:

3. 選択的ハイドレーション(サーバーサイドレンダリング - SSRの場合)

サーバーサイドレンダリング(SSR)を使用する場合、Suspenseを使用してページの特定の部分を選択的にハイドレーションできます。これは、ページの最も重要な部分を先にハイドレーションすることを優先できることを意味し、インタラクティブまでの時間(TTI)と知覚されるパフォーマンスを向上させます。これは、あまり重要でないコンポーネントのハイドレーションを延期しながら、基本的なレイアウトやコアコンテンツをできるだけ早く表示したいシナリオに役立ちます。

例(概念):

// サーバーサイド:
<Suspense fallback={<div>クリティカルコンテンツをロード中...</div>}>
  <CriticalContent />
</Suspense>
<Suspense fallback={<div>オプションコンテンツをロード中...</div>}>
  <OptionalContent />
</Suspense>

説明:

利点:

欠点:

4. Suspense対応のデータ取得ライブラリ

いくつかの人気のあるデータ取得ライブラリには、React Suspenseの組み込みサポートがあります。これらのライブラリは、データの取得とSuspenseとの統合を、より便利で効率的な方法で提供することがよくあります。いくつかの注目すべき例は次のとおりです。

例(SWRを使用):

import useSWR from 'swr'

const fetcher = (...args) => fetch(...args).then(res => res.json())

function UserProfile() {
  const { data: user, error } = useSWR('/api/user/123', fetcher, { suspense: true })

  if (error) return <div>ロードに失敗しました</div>
  if (!user) return <div>ロード中...</div> // Suspenseを使用している場合、これはおそらくレンダリングされません

  return (
    <div>
      <h2>{user.name}</h2>
      <p>Email: {user.email}</p>
    </div>
  )
}

function App() {
  return (
    <Suspense fallback={<div>ユーザーデータをロード中...</div>}>
      <UserProfile />
    </Suspense>
  );
}

説明:

利点:

欠点:

Suspenseを使用したエラーハンドリング

Suspenseを使用する際のエラーハンドリングは不可欠です。Reactは、Suspense境界内で発生したエラーをキャッチするためのErrorBoundaryコンポーネントを提供します。

例:

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    // 次のレンダリングでフォールバックUIが表示されるように状態を更新します。
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo) {
    // エラーをエラー報告サービスにログすることもできます
    console.error(error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      // カスタムフォールバックUIをレンダリングできます
      return <h1>何かが間違っています。</h1>;
    }

    return this.props.children;
  }
}

function App() {
  return (
    <ErrorBoundary>
      <Suspense fallback={<div>ロード中...</div>}>
        <UserProfile />
      </Suspense>
    </ErrorBoundary>
  );
}

説明:

React Suspenseの使用に関するベストプラクティス

実際的な例

React Suspenseは、次のようなさまざまなシナリオに適用できます。

例1:国際的なEコマースプラットフォーム

さまざまな国の顧客にサービスを提供するEコマースプラットフォームを想像してみてください。価格や説明などの製品詳細は、ユーザーの場所に基づいて取得する必要がある場合があります。Suspenseを使用して、ローカライズされた製品情報を取得している間、ローディングインジケータを表示できます。

function ProductDetails({ productId, locale }) {
  const productResource = fetchData(`/api/products/${productId}?locale=${locale}`);
  const product = productResource.read();

  return (
    <div>
      <h2>{product.name}</h2>
      <p>Price: {product.price}</p>
      <p>Description: {product.description}</p>
    </div>
  );
}

function App() {
  const userLocale = getUserLocale(); // ユーザーのロケールを決定する関数
  return (
    <Suspense fallback={<div>製品詳細をロード中...</div>}>
      <ProductDetails productId="123" locale={userLocale} />
    </Suspense>
  );
}

例2:グローバルソーシャルメディアフィード

世界中のユーザーからの投稿のフィードを表示するソーシャルメディアプラットフォームを検討してください。各投稿には、テキスト、画像、動画が含まれる場合があり、ロードにさまざまな時間がかかる可能性があります。Suspenseを使用して、個々の投稿のプレースホルダーを表示しながら、コンテンツがロードされるようにすることで、よりスムーズなスクロールエクスペリエンスを提供できます。

function Post({ postId }) {
  const postResource = fetchData(`/api/posts/${postId}`);
  const post = postResource.read();

  return (
    <div>
      <p>{post.text}</p>
      {post.image && <img src={post.image} alt="Post Image" />}
      {post.video && <video src={post.video} controls />}
    </div>
  );
}

function App() {
  const postIds = getPostIds(); // post IDのリストを取得する関数
  return (
    <div>
      {postIds.map(postId => (
        <Suspense key={postId} fallback={<div>投稿をロード中...</div>}>
          <Post postId={postId} />
        </Suspense>
      ))}
    </div>
  );
}

結論

React Suspenseは、Reactアプリケーションでの非同期データ取得を管理するための強力なツールです。さまざまなデータ取得戦略とベストプラクティスを理解することで、優れたユーザーエクスペリエンスを提供する、応答性の高い、ユーザーフレンドリーで、パフォーマンスの高いアプリケーションを構築できます。特定 のニーズに最適なアプローチを見つけるために、さまざまな戦略やライブラリを試してみてください。

Reactが進化し続けるにつれて、Suspenseはデータ取得とレンダリングにおいてさらに重要な役割を果たす可能性が高いです。最新の開発とベストプラクティスに関する情報を入手することで、この機能の可能性を最大限に活用できます。