# React NativeとGraphQL 2026年版: Apollo Client、クエリ、面接対策
> Apollo Client 4.0を使用してReact NativeにGraphQLを統合する方法を解説します。クエリ、ミューテーション、キャッシュ戦略、モバイルGraphQL開発の面接質問についても詳しく説明します。
- Published: 2026-08-20
- Updated: 2026-08-20
- Author: Anthony Fillion-Maillet
- Tags: react-native, graphql, apollo-client, mobile, api, interview
- Reading time: 9 min
---
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`が必要です。
```typescript
// src/apollo/client.ts
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のレイアウトでルートレベルに配置します。
```tsx
// App.tsx
import { ApolloProvider } from '@apollo/client/react';
import { apolloClient } from './src/apollo/client';
import { RootNavigator } from './src/navigation';
export default function App() {
return (
);
}
```
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設定はスキーマを指定し、出力場所を指定します。
```typescript
// codegen.ts
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が導入されています。
```tsx
// src/screens/ProductListScreen.tsx
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 Error: {error.message};
}
const loadMore = () => {
fetchMore({
variables: { offset: data?.products.length ?? 0 },
});
};
return (
item.id}
renderItem={({ item }) => }
onEndReached={loadMore}
onEndReachedThreshold={0.5}
ListFooterComponent={loading ? : null}
/>
);
}
```
`cache-and-network`フェッチポリシーは、サーバーからのリフレッシュ中にキャッシュデータを即座に表示します。このパターンはモバイルネットワークでの体感遅延を軽減します。
## ミューテーションと楽観的更新
ミューテーションはサーバーデータを変更し、ローカルキャッシュを更新します。楽観的レスポンスは、サーバーが変更を確認する前に即座のフィードバックを提供します。
```tsx
// src/hooks/useAddToCart.ts
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()`メソッドにより、型安全なエラー処理が可能になります。
```tsx
// src/components/ErrorBoundary.tsx
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 (
Connection failed. Check your internet.
);
}
// GraphQL validation or resolver errors
if (GraphQLErrors.is(error)) {
const firstError = error.graphQLErrors[0];
if (firstError?.extensions?.code === 'UNAUTHENTICATED') {
return Session expired. Please log in again.;
}
return Request failed: {firstError?.message};
}
return Something went wrong;
}
```
ネットワークエラーとGraphQLエラーを区別することで、異なる回復戦略が可能になります。一時的な障害にはリトライ、認証の問題にはリダイレクトを行います。
## キャッシュ永続化によるオフラインサポート
モバイルアプリは、以前に取得したデータへのオフラインアクセスが必要です。`apollo3-cache-persist`ライブラリはキャッシュをAsyncStorageにシリアライズします。
```typescript
// src/apollo/persistence.ts
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](https://github.com/enisdenjo/graphql-ws)プロトコルをサポートしています。
```typescript
// src/apollo/client.ts
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は`__typename`と`id`でレスポンスを正規化し、各エンティティを一度だけ保存します。クエリはキャッシュキーで正規化されたオブジェクトを参照します。この重複排除によりメモリを節約し、一貫性を確保します。あるリストで商品を更新すると、すべての場所で更新されます。
### 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](https://www.apollographql.com/docs/react/api/link/introduction/)を使用してすべてのリクエストにトークンを添付することです。
```typescript
// src/apollo/authLink.ts
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拡張機能](https://marketplace.visualstudio.com/items?itemName=apollographql.vscode-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防止などのモバイル固有のトレードオフに焦点を当てています。
---
Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack.
HTML version of this page: https://sharpskill.dev/ja/blog/react-native/react-native-graphql-apollo-client-queries-interview