部分的にキャッシュされたデータのレンダリング
Relayでキャッシュされたデータをレンダリングする場合、部分レンダリングを実行することが可能です。私たちは、*「部分レンダリング」*を、部分的にキャッシュされたクエリを即座にレンダリングする機能と定義します。つまり、クエリの 一部は欠落している可能性がありますが、クエリの 一部は既にキャッシュされている可能性があります。このような場合、クエリ全体がフェッチされるのを待たずに、キャッシュされているクエリの 一部を即座にレンダリングできるようにしたいと考えています。
これは、画面やページをできるだけ早くレンダリングしたい場合に役立ちます。そのページの一部のデータが既にキャッシュされていることがわかっているため、読み込み状態をスキップできます。たとえば、プロフィールページを考えてみましょう。アプリの使用中にユーザーの名前が既にキャッシュされている可能性が非常に高いため、プロフィールページにアクセスしたときに、ユーザーの名前がキャッシュされている場合は、プロフィールページの残りのデータがまだ利用できない場合でも、すぐにレンダリングしたいと考えています。
部分レンダリングの境界としてのフラグメント
これを実現するために、フラグメントコンポーネントの*サスペンド*機能に依存します(Suspenseによる読み込み状態セクションを参照)。フラグメントコンポーネントは、レンダリング中にローカルで宣言されたデータの一部が欠落していて、現在フェッチされている場合にサスペンドします。具体的には、必要なデータがフェッチされるまで、つまり、属するクエリ(その*親クエリ*)がフェッチされるまでサスペンドします。
例を使ってこれを説明しましょう。次のフラグメントコンポーネントがあるとします。
/**
 * UsernameComponent.react.js
 *
 * Fragment Component
 */
import type {UsernameComponent_user$key} from 'UsernameComponent_user.graphql';
const React = require('React');
const {graphql, useFragment} = require('react-relay');
type Props = {
  user: UsernameComponent_user$key,
};
function UsernameComponent(props: Props) {
  const user = useFragment(
    graphql`
      fragment UsernameComponent_user on User {
        username
      }
    `,
    props.user,
  );
  return (...);
}
module.exports = UsernameComponent;
また、いくつかのデータをクエリし、上記のフラグメントも含む、次のクエリコンポーネントがあるとします。
/**
 * AppTabs.react.js
 *
 * Query Loader Component
 */
 // ....
  const onSelectHomeTab = () => {
    loadHomeTabQuery({id: '4'}, {fetchPolicy: 'store-or-network'});
  }
 // ...
/**
 * HomeTab.react.js
 *
 * Query Component
 */
const React = require('React');
const {graphql, usePreloadedQuery} = require('react-relay');
const UsernameComponent = require('./UsernameComponent.react');
function HomeTab(props: Props) {
  const data = usePreloadedQuery(
    graphql`
      query HomeTabQuery($id: ID!) {
        user(id: $id) {
          name
          ...UsernameComponent_user
        }
      }
    `,
    props.queryRef,
  );
  return (
    <>
      <h1>{data.user?.name}</h1>
      <UsernameComponent user={data.user} />
    </>
  );
}
この`HomeTab`コンポーネントがレンダリングされるとき、`{id: 4}`の`User`の`name`(*のみ*)を既に以前にフェッチしており、現在のRelay環境に関連付けられたRelayストアにローカルにキャッシュされているとします。
ローカルにキャッシュされたデータの再利用を許可する`fetchPolicy`(`'store-or-network'`または`'store-and-network'`)を使用してクエリをレンダリングしようとすると、次のようになります。
- クエリは、ローカルに必要なデータが欠落しているかどうかを確認します。この場合、*欠落していません*。具体的には、クエリは`name`フィールドのみを直接選択しており、そのフィールドはストアで*利用可能です*。- Relayは、ローカルで宣言されていて欠落している場合にのみ、データを欠落していると見なします。言い換えれば、フラグメントスプレッド内で選択されたデータは、外側のクエリまたはフラグメントにデータが欠落していると判断されるかどうかに影響しません。
 
- クエリにデータが欠落していない場合、クエリはレンダリングされ、次に子`UsernameComponent`のレンダリングを試みます。
- `UsernameComponent`が`UsernameComponent_user`フラグメントをレンダリングしようとすると、Relayはレンダリングに必要なデータの一部が欠落していることに気付きます。具体的には、`username`が欠落しています。この時点で、`UsernameComponent`にはデータが欠落しているため、ネットワークリクエストが完了するまでレンダリングをサスペンドします。選択した`fetchPolicy`に関係なく、フラグメントを含むクエリ全体のデータの一部が欠落している場合、常にネットワークリクエストが開始されます。
この時点で、`UsernameComponent`が欠落している`username`のためにサスペンドすると、理想的には、`User`の`name`がローカルにキャッシュされているため、すぐにレンダリングできるはずです。ただし、`Suspense`コンポーネントを使用してフラグメントのサスペンションをキャッチしていないため、サスペンションはバブルアップし、`App`コンポーネント全体がサスペンドされます。
`username`が欠落している場合でも`name`が利用可能なときにレンダリングするという望ましい効果を実現するには、`UsernameComponent`を`Suspense`でラップして、`App`の他の部分がレンダリングを続行できるようにするだけです。
/**
 * HomeTab.react.js
 *
 * Query Component
 */
const React = require('React');
const {Suspense} = require('React');
const {graphql, usePreloadedQuery} = require('react-relay');
const UsernameComponent = require('./UsernameComponent.react');
function HomeTab() {
  const data = usePreloadedQuery(
    graphql`
      query AppQuery($id: ID!) {
        user(id: $id) {
          name
          ...UsernameComponent_user
        }
      }
    `,
    props.queryRef,
  );
  return (
    <>
      <h1>{data.user?.name}</h1>
      {/*
        Wrap the UserComponent in Suspense to allow other parts of the
        App to be rendered even if the username is missing.
      */}
      <Suspense fallback={<LoadingSpinner label="Fetching username" />}>
        <UsernameComponent user={data.user} />
      </Suspense>
    </>
  );
}
上記で説明したプロセスは、ネストされたフラグメント(つまり、他のフラグメント内に含まれるフラグメント)でも同じように機能します。これは、フラグメントのレンダリングに必要なデータがローカルにキャッシュされている場合、子孫フラグメントのデータが欠落しているかどうかに関係なく、フラグメントコンポーネントをレンダリングできることを意味します。子フラグメントのデータが欠落している場合は、`Suspense`コンポーネントでラップして、他のフラグメントとアプリの 一部がレンダリングを続行できるようにすることができます。
動機付けの例で述べたように、これは読み込み状態を完全にスキップできるため望ましいことです。より具体的には、部分的に利用可能なデータをレンダリングする機能により、最終的にレンダリングされた状態により近い中間UI状態をレンダリングできます。
このページは役に立ちましたか?
いくつかの簡単な質問に答えることで、サイトの改善にご協力ください 簡単な質問に答えることで.