メインコンテンツにスキップ
バージョン: v18.0.0

Suspense を使用したローディング状態

既にお気づきかもしれませんが、usePreloadedQueryuseLazyLoadQuery を使用すると、サーバーからフェッチされたクエリからデータをレンダリングすると述べましたが、そのデータがまだフェッチされている間、ローディング UI (きらめきなど) をレンダリングする方法については詳しく説明しませんでした。このセクションでそれについて説明します。

クエリのフェッチ中にローディング状態をレンダリングするには、React Suspense に依存します。Suspense は、コード、画像、データなどの非同期リソースがロードされるのを待つために、コンポーネントがレンダリングを中断または「一時停止」できるようにする React の新機能です。コンポーネントが「一時停止」すると、React に対して、コンポーネントがまだレンダリングする「準備ができていない」こと、および待機している非同期リソースがロードされるまで準備ができないことを示します。リソースが最終的にロードされると、React はコンポーネントを再度レンダリングしようとします。

この機能は、コンポーネントがレンダリングするために必要なデータ、コード、画像などの非同期依存関係を表現するのに役立ち、これらの非同期リソースが利用可能になったときに、コンポーネントツリー全体でローディング状態のレンダリングを React が調整できるようにします。より一般的には、Suspense を使用すると、アプリが初めてロードされるときや、異なる状態に移行するときに、より意図的に設計されたローディング状態を実装するためのより優れた制御が得られ、ロードシーケンスが明示的に設計および調整されていない場合に一般的に発生する可能性のある、ローディング要素 (スピナーなど) の偶発的なちらつきを防ぐのに役立ちます。

注意

これは、「データフェッチ用の Suspense」が一般的な実装と採用の準備ができていることを意味するものではありませんデータフェッチ用の Suspense のサポート、一般的なガイダンス、および使用要件はまだ準備ができておらず、React チームは今後の React リリースでこのガイダンスがどのようなものになるかをまだ定義しています。

React 17 で Suspense を使用する場合にいくつかの制限がありますが、Relay Hooks は安定しており、今後の React リリースをサポートする方向に向かっています。

詳細については、Suspense の互換性ガイドを参照してください。

Suspense バウンダリを使用したローディングフォールバック

コンポーネントが一時停止された場合、「準備ができた」状態になるのを待つ間、コンポーネントの代わりにフォールバックをレンダリングする必要があります。これを行うには、React が提供する Suspense コンポーネントを使用します。

const React = require('React');
const {Suspense} = require('React');

function App() {
return (
// Render a fallback using Suspense as a wrapper
<Suspense fallback={<LoadingGlimmer />}>
<CanSuspend />
</Suspense>
);
}

Suspense コンポーネントは、任意のコンポーネントをラップするために使用できます。ターゲットコンポーネントが一時停止した場合、Suspense は、すべての子孫が「準備ができた」状態になるまで (つまり、サブツリー内のすべての一時停止されたコンポーネントが解決するまで)、提供されたフォールバックをレンダリングします。通常、フォールバックは、きらめきやプレースホルダーなどのフォールバックローディング状態をレンダリングするために使用されます。

通常、アプリ内のさまざまなコンテンツが一時停止する可能性があるため、Suspense を使用して、それらが解決されるまでローディング状態を表示できます。

/**
* App.react.js
*/

const React = require('React');
const {Suspense} = require('React');

function App() {
return (
// LoadingGlimmer is rendered via the Suspense fallback
<Suspense fallback={<LoadingGlimmer />}>
<MainContent /> {/* MainContent may suspend */}
</Suspense>
);
}

ここで何が起こっているのかを分析してみましょう

  • MainContent が一部の非同期リソース (データなど) を待機しているために一時停止した場合、MainContent をラップする Suspense コンポーネントは、一時停止したことを検出し、MainContent がレンダリングできるようになるまで、fallback 要素 (この場合は LoadingGlimmer) をレンダリングします。これは、一時停止する可能性のある MainContent の子孫も推移的に含まれることに注意してください。

Suspense の素晴らしい点は、コンポーネントツリーのさまざまな部分のローディング状態をどのように累積するかを細かく制御できることです。

/**
* App.react.js
*/

const React = require('React');
const {Suspense} = require('React');

function App() {
return (
// A LoadingGlimmer for all content is rendered via the Suspense fallback
<Suspense fallback={<LoadingGlimmer />}>
<MainContent />
<SecondaryContent /> {/* SecondaryContent can also suspend */}
</Suspense>
);
}
  • この場合、MainContentSecondaryContent は両方とも、非同期リソースをロード中に一時停止する可能性があります。両方を Suspense でラップすることで、すべてが準備完了になるまで単一のローディング状態を表示し、すべてが正常にロードされた後、コンテンツ全体を単一のペイントでレンダリングできます。
  • 実際、MainContentSecondaryContent は、データフェッチ以外のさまざまな理由で一時停止する可能性がありますが、同じ Suspense コンポーネントを使用して、サブツリー内のすべてのコンポーネントがレンダリング可能になるまでフォールバックをレンダリングできます。これは、一時停止する可能性のある MainContent または SecondaryContent の子孫も推移的に含まれることに注意してください。

逆に、ローディング UI についてより細かく決定し、コンポーネントツリーの小さいまたは個々の部分の周りに Suspense コンポーネントをラップすることもできます。

/**
* App.react.js
*/

const React = require('React');
const {Suspense} = require('React');

function App() {
return (
<>
{/* Show a separate loading UI for the LeftHandColumn */}
<Suspense fallback={<LeftColumnPlaceholder />}>
<LeftColumn />
</Suspense>

{/* Show a separate loading UI for both the Main and Secondary content */}
<Suspense fallback={<LoadingGlimmer />}>
<MainContent />
<SecondaryContent />
</Suspense>
</>
);
}
  • この場合、2 つの異なるローディング UI を表示しています。
    • LeftColumn の準備が整うまで表示されるもの。
    • そして、MainContentSecondaryContent の両方が準備完了になるまで表示されるもの。
  • この強力な点は、コンポーネントを Suspense でより細かくラップすることにより、他のコンポーネントが準備完了になり次第、より早くレンダリングできるようになることです。この例では、MainContentSecondaryContentSuspense の下に個別にラップすることで、コンテンツセクションの準備が整うよりも早く、LeftColumn が準備でき次第レンダリングできるようになります。

一時停止するトランジションと更新

Suspense バウンダリフォールバックを使用すると、一部のコンテンツを最初にレンダリングするときのローディングプレースホルダーを記述できますが、アプリケーションには異なるコンテンツ間のトランジションも含まれます。特に、すでにマウントされているバウンダリ内の 2 つのコンポーネントを切り替える場合、切り替え先の新しいコンポーネントがすべての非同期依存関係をロードしていない可能性があり、これは一時停止する可能性もあることを意味します。

このような場合でも、Suspense バウンダリフォールバックが表示されます。ただし、これは、Suspense フォールバックを表示するために既存のコンテンツを非表示にすることを意味します。同時レンダリングがサポートされる今後の React バージョンでは、React はこのケースをサポートし、一時停止時に Suspense フォールバックで既にレンダリングされたコンテンツを非表示にしないオプションを提供します。

Relay での Suspense の使用方法

クエリ

この場合、クエリコンポーネントは一時停止できるコンポーネントであるため、Suspense を使用して、クエリのフェッチ中にローディング状態をレンダリングします。実際にどのように見えるか見てみましょう

次のクエリレンダラーコンポーネントがあるとします。

/**
* MainContent.react.js
*
* Query Component
*/

const React = require('React');
const {graphql, usePreloadedQuery} = require('react-relay');

function MainContent(props) {
// Fetch and render a query
const data = usePreloadedQuery(
graphql`...`,
props.queryRef,
);

return (...);
}
/**
* App.react.js
*/

const React = require('React');
const {Suspense} = require('React');

function App() {
return (
// LoadingGlimmer is rendered via the Suspense fallback
<Suspense fallback={<LoadingGlimmer />}>
<MainContent /> {/* MainContent may suspend */}
</Suspense>
);
}

ここで何が起こっているのかを分析してみましょう

  • クエリをフェッチしてレンダリングするクエリレンダラーである MainContent コンポーネントがあります。MainContent は、クエリをフェッチしようとするとレンダリングを一時停止し、まだレンダリングの準備ができていないことを示し、クエリがフェッチされると解決されます。
  • MainContent をラップする Suspense コンポーネントは、MainContent が一時停止したことを検出し、MainContent がレンダリングできるようになるまで、つまりクエリがフェッチされるまで、fallback 要素 (この場合は LoadingGlimmer) をレンダリングします。

フラグメント

フラグメントは、@defer' されているデータ、または Relay ストアで部分的に利用可能なデータ (つまり、部分的なレンダリング) のレンダリングをサポートするために、Suspense とも統合されています。

トランジション

さらに、リフェッチ ( リフレッシュとリフェッチ ) と 接続のレンダリング のための API も Suspense と統合されています。これらのユースケースでは、これらの API も一時停止します。


このページは役に立ちましたか?

いくつかの簡単な質問に答えて、サイトをさらに改善にご協力ください。 いくつかの簡単な質問に回答する.