React NativeとGraphQL 2026年版: Apollo Client、クエリ、面接対策

Apollo Client 4.0を使用してReact NativeにGraphQLを統合する方法を解説します。クエリ、ミューテーション、キャッシュ戦略、モバイルGraphQL開発の面接質問についても詳しく説明します。

React NativeとGraphQLの統合、Apollo Clientコードアーキテクチャ

GraphQLは、柔軟なデータ取得と効率的なネットワーク使用を必要とするReact Nativeアプリケーションにおいて、優先的なAPIレイヤーとなっています。2025年後半にリリースされたApollo Client 4.0は、モバイル環境向けに特別に設計された、20〜30%小さいバンドルサイズと改善されたTypeScriptサポートを備えた軽量アーキテクチャを提供します。

Apollo Client 4.0の主な変更点

Apollo Client 4.0では、React固有のエクスポートが@apollo/client/reactに分離されました。React 19のSuspenseとReact Compilerをサポートし、モノリシックなApolloErrorがデバッグ改善のための特定のエラークラスに置き換えられています。

React NativeでのApollo Client 4のセットアップ

インストールプロセスはシンプルです。Apollo Client 4.0はExpoプロジェクトとベアReact Nativeプロジェクトの両方で動作します。

bash
# Installation
npm install @apollo/client graphql

クライアントの初期化には、ネットワークリクエスト用のHttpLinkとローカル状態管理用のInMemoryCacheが必要です。

src/apollo/client.tstypescript
import { ApolloClient, InMemoryCache, HttpLink } from '@apollo/client';

const httpLink = new HttpLink({
  uri: 'https://api.example.com/graphql',
  // Enable text streaming for @defer and subscriptions
  fetchOptions: {
    reactNative: { textStreaming: true },
  },
});

export const apolloClient = new ApolloClient({
  link: httpLink,
  cache: new InMemoryCache({
    typePolicies: {
      Query: {
        fields: {
          // Merge paginated results
          products: {
            keyArgs: ['category'],
            merge(existing = [], incoming) {
              return [...existing, ...incoming];
            },
          },
        },
      },
    },
  }),
});

typePoliciesの設定は、無限スクロールを持つモバイルアプリで一般的な要件であるページネーションデータのキャッシュ正規化を処理します。

ApolloProviderでアプリをラップする

プロバイダーパターンはApollo ClientをReactコンポーネントツリーに接続します。通常はApp.tsxまたはExpo Routerのレイアウトでルートレベルに配置します。

App.tsxtsx
import { ApolloProvider } from '@apollo/client/react';
import { apolloClient } from './src/apollo/client';
import { RootNavigator } from './src/navigation';

export default function App() {
  return (
    <ApolloProvider client={apolloClient}>
      <RootNavigator />
    </ApolloProvider>
  );
}

Apollo Client 4.0では、ReactフックはメインエントリポイントではなくApollo/client/react`からインポートします。この変更により、コアクライアントがReact以外のコンテキストで実行される場合のバンドルサイズが削減されます。

型安全なGraphQLクエリの作成

GraphQL Code Generatorはスキーマから TypeScript型を生成し、実行時の型の不一致を排除します。クライアントプラグインと一緒にインストールします。

bash
# Install codegen tools
npm install -D @graphql-codegen/cli @graphql-codegen/client-preset

codegen設定はスキーマを指定し、出力場所を指定します。

codegen.tstypescript
import type { CodegenConfig } from '@graphql-codegen/cli';

const config: CodegenConfig = {
  schema: 'https://api.example.com/graphql',
  documents: ['src/**/*.tsx', 'src/**/*.ts'],
  generates: {
    './src/gql/': {
      preset: 'client',
      config: {
        documentMode: 'string',
      },
    },
  },
};

export default config;

npx graphql-codegenを実行すると、useQueryフックが使用する型付きドキュメントノードが生成されます。

useQueryによるデータ取得

useQueryフックは、ローディング状態、エラー、キャッシュ更新を管理します。Apollo Client 4.0では、より予測可能な状態遷移のためのdataState APIが導入されています。

src/screens/ProductListScreen.tsxtsx
import { useQuery } from '@apollo/client/react';
import { graphql } from '../gql';
import { ActivityIndicator, FlatList, Text, View } from 'react-native';

const GET_PRODUCTS = graphql(`
  query GetProducts($category: String!, $limit: Int, $offset: Int) {
    products(category: $category, limit: $limit, offset: $offset) {
      id
      name
      price
      imageUrl
    }
  }
`);

export function ProductListScreen({ category }: { category: string }) {
  const { data, loading, error, fetchMore } = useQuery(GET_PRODUCTS, {
    variables: { category, limit: 20, offset: 0 },
    // Fetch from cache first, then network
    fetchPolicy: 'cache-and-network',
    // Keep previous data while fetching new
    notifyOnNetworkStatusChange: true,
  });

  if (error) {
    return <Text>Error: {error.message}</Text>;
  }

  const loadMore = () => {
    fetchMore({
      variables: { offset: data?.products.length ?? 0 },
    });
  };

  return (
    <FlatList
      data={data?.products ?? []}
      keyExtractor={(item) => item.id}
      renderItem={({ item }) => <ProductCard product={item} />}
      onEndReached={loadMore}
      onEndReachedThreshold={0.5}
      ListFooterComponent={loading ? <ActivityIndicator /> : null}
    />
  );
}

cache-and-networkフェッチポリシーは、サーバーからのリフレッシュ中にキャッシュデータを即座に表示します。このパターンはモバイルネットワークでの体感遅延を軽減します。

React Nativeの面接対策はできていますか?

インタラクティブなシミュレーター、flashcards、技術テストで練習しましょう。

ミューテーションと楽観的更新

ミューテーションはサーバーデータを変更し、ローカルキャッシュを更新します。楽観的レスポンスは、サーバーが変更を確認する前に即座のフィードバックを提供します。

src/hooks/useAddToCart.tstsx
import { useMutation } from '@apollo/client/react';
import { graphql } from '../gql';

const ADD_TO_CART = graphql(`
  mutation AddToCart($productId: ID!, $quantity: Int!) {
    addToCart(productId: $productId, quantity: $quantity) {
      id
      items {
        id
        product {
          id
          name
        }
        quantity
      }
      totalPrice
    }
  }
`);

export function useAddToCart() {
  const [addToCart, { loading }] = useMutation(ADD_TO_CART, {
    // Optimistic response for instant UI feedback
    optimisticResponse: ({ productId, quantity }) => ({
      addToCart: {
        __typename: 'Cart',
        id: 'current-cart',
        items: [],
        totalPrice: 0,
      },
    }),
    // Update cache after mutation
    update(cache, { data }) {
      if (!data?.addToCart) return;
      cache.modify({
        id: cache.identify({ __typename: 'Cart', id: 'current-cart' }),
        fields: {
          items: () => data.addToCart.items,
          totalPrice: () => data.addToCart.totalPrice,
        },
      });
    },
  });

  return { addToCart, loading };
}

cache.modifyメソッドは、クエリ全体を再取得せずにキャッシュされたフィールドを直接更新します。このアプローチはセルラー接続でのネットワークリクエストを最小限に抑えます。

モバイルアプリでのネットワークエラー処理

Apollo Client 4.0では、汎用のApolloErrorが特定のエラークラスに置き換えられています。静的な.is()メソッドにより、型安全なエラー処理が可能になります。

src/components/ErrorBoundary.tsxtsx
import { NetworkError, GraphQLErrors } from '@apollo/client/errors';
import { Text, Button, View } from 'react-native';

interface Props {
  error: Error;
  onRetry: () => void;
}

export function QueryErrorHandler({ error, onRetry }: Props) {
  // Network failure (offline, timeout, DNS)
  if (NetworkError.is(error)) {
    return (
      <View>
        <Text>Connection failed. Check your internet.</Text>
        <Button title="Retry" onPress={onRetry} />
      </View>
    );
  }

  // GraphQL validation or resolver errors
  if (GraphQLErrors.is(error)) {
    const firstError = error.graphQLErrors[0];
    if (firstError?.extensions?.code === 'UNAUTHENTICATED') {
      return <Text>Session expired. Please log in again.</Text>;
    }
    return <Text>Request failed: {firstError?.message}</Text>;
  }

  return <Text>Something went wrong</Text>;
}

ネットワークエラーとGraphQLエラーを区別することで、異なる回復戦略が可能になります。一時的な障害にはリトライ、認証の問題にはリダイレクトを行います。

キャッシュ永続化によるオフラインサポート

モバイルアプリは、以前に取得したデータへのオフラインアクセスが必要です。apollo3-cache-persistライブラリはキャッシュをAsyncStorageにシリアライズします。

src/apollo/persistence.tstypescript
import AsyncStorage from '@react-native-async-storage/async-storage';
import { persistCache } from 'apollo3-cache-persist';
import { apolloClient } from './client';

export async function initializeCache() {
  await persistCache({
    cache: apolloClient.cache,
    storage: AsyncStorage,
    maxSize: 1024 * 1024 * 5, // 5 MB limit
    debounce: 1000, // Write at most once per second
  });
}

アプリをレンダリングする前にinitializeCacheを呼び出して、ディスクからキャッシュデータを復元します。ユーザーはネットワークアクセスがなくても、最後に取得したコンテンツを即座に見ることができます。

GraphQLサブスクリプションによるリアルタイム更新

サブスクリプションはWebSocket経由でサーバーイベントをクライアントにプッシュします。Apollo Client 4.0は新しいgraphql-wsプロトコルをサポートしています。

src/apollo/client.tstypescript
import { split, HttpLink, ApolloClient, InMemoryCache } from '@apollo/client';
import { GraphQLWsLink } from '@apollo/client/link/subscriptions';
import { createClient } from 'graphql-ws';
import { getMainDefinition } from '@apollo/client/utilities';

const httpLink = new HttpLink({ uri: 'https://api.example.com/graphql' });

const wsLink = new GraphQLWsLink(
  createClient({
    url: 'wss://api.example.com/graphql',
    connectionParams: async () => ({
      authToken: await getStoredToken(),
    }),
  })
);

// Route subscriptions to WebSocket, others to HTTP
const splitLink = split(
  ({ query }) => {
    const definition = getMainDefinition(query);
    return (
      definition.kind === 'OperationDefinition' &&
      definition.operation === 'subscription'
    );
  },
  wsLink,
  httpLink
);

export const apolloClient = new ApolloClient({
  link: splitLink,
  cache: new InMemoryCache(),
});

split関数は、オペレーションタイプに基づいてオペレーションを適切なトランスポートに振り分けます。

面接でよく聞かれる質問: React Native GraphQL

技術面接では、GraphQLのモバイル固有のトレードオフについての理解がよく問われます。以下の質問はReact Nativeポジションで頻繁に出題されます。

モバイルアプリでRESTよりGraphQLを選ぶ理由は?

GraphQLは要求されたフィールドのみを返すことでオーバーフェッチを削減します。単一のクエリが複数のRESTエンドポイントを置き換え、高遅延のセルラー接続でのラウンドトリップを削減します。型付きスキーマによりコンパイル時の検証が可能になり、実行時前にAPIの不一致を検出できます。

Apollo Clientはどのようにデータをキャッシュしますか?

Apolloは__typenameidでレスポンスを正規化し、各エンティティを一度だけ保存します。クエリはキャッシュキーで正規化されたオブジェクトを参照します。この重複排除によりメモリを節約し、一貫性を確保します。あるリストで商品を更新すると、すべての場所で更新されます。

Apollo Clientがサポートするフェッチポリシーは?

ポリシー動作ユースケース
cache-firstキャッシュがあれば返し、なければフェッチデフォルト、リクエスト最小化
cache-and-networkキャッシュを即座に返し、ネットワークから更新即時表示で新鮮なデータ
network-only常にフェッチ、キャッシュを更新古いデータが許容できない場合
cache-onlyフェッチせず、キャッシュにない場合は失敗オフラインモード
no-cacheキャッシュせずにフェッチ機密データ

楽観的更新はどのように機能しますか?

クライアントはミューテーション結果を予測し、サーバーが応答する前にキャッシュを更新します。サーバーが異なる結果を返した場合、Apolloは楽観的データを実際のレスポンスで置き換えます。ミューテーションが失敗した場合、Apolloは前の状態にロールバックします。

GraphQLでN+1問題が発生する原因は?

関連データを個別にフェッチするネストされたリゾルバーがN+1クエリを作成します。50個の商品とそのカテゴリをリクエストすると、1つの商品クエリと50のカテゴリクエリがトリガーされます。サーバーサイドのDataLoaderがこれらを単一のクエリにバッチ処理します。

Apollo Clientで認証トークンをどのように処理しますか?

推奨されるアプローチは、Apollo Linkを使用してすべてのリクエストにトークンを添付することです。

src/apollo/authLink.tstypescript
import { setContext } from '@apollo/client/link/context';
import { getStoredToken } from '../auth/storage';

export const authLink = setContext(async (_, { headers }) => {
  const token = await getStoredToken();
  return {
    headers: {
      ...headers,
      authorization: token ? `Bearer ${token}` : '',
    },
  };
});

このリンクをクライアント設定のHttpLinkの前にチェーンします。

React NativeでのGraphQLデバッグ

ApolloはReact Native開発のための複数のデバッグオプションを提供しています。VS Code Apollo拡張機能には、キャッシュ内容とクエリ履歴を表示する組み込みのClient DevToolsが含まれています。

スタンドアロンデバッグには、Flipperがコミュニティプラグインreact-native-apollo-devtoolsと統合されています。このプラグインはキャッシュ状態を検査し、進行中のクエリを監視し、ミューテーションを再生します。

React Native Debuggerによるネットワーク検査には、「Debug JS Remotely」を有効にする必要があります。その後、Networkタブにリクエストとレスポンスボディを含むGraphQLペイロードが表示されます。

モバイルGraphQL開発の重要ポイント

  • Apollo Client 4.0は、ESMファーストのパッケージングと分離されたReactエクスポートにより、バンドルサイズを20〜30%削減します。
  • cache-and-networkフェッチポリシーは、低速接続での即時表示とデータの新鮮さのバランスを取ります。
  • 楽観的更新は即座のフィードバックを提供し、cache.modifyは不要な再フェッチを回避します。
  • Apollo Client 4.0の型付きエラークラスにより、ネットワーク障害とGraphQLエラーの特定の処理が可能になります。
  • apollo3-cache-persistによるキャッシュ永続化により、以前に取得したデータへのオフラインアクセスが可能になります。
  • GraphQLサブスクリプションにはgraphql-wsプロトコルとsplit link設定が必要です。
  • 面接の質問は、キャッシュ戦略、フェッチポリシー、N+1防止などのモバイル固有のトレードオフに焦点を当てています。

今すぐ練習を始めましょう!

面接シミュレーターと技術テストで知識をテストしましょう。

今日のチャレンジ

React Native のバグを見つけられますか

実際のコード、隠れたバグ、1日1回。アカウントなしで試せます。

Anthony Fillion-Maillet

執筆

Anthony Fillion-Maillet

SharpSkill 創業者

10 年以上フルスタック開発に携わっています。SharpSkill を運営し、ここで公開される内容に責任を負っています。

2026年8月20日 更新

タグ

#react-native
#graphql
#apollo-client
#mobile
#api
#interview

共有

関連記事