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

GraphQLは、柔軟なデータ取得と効率的なネットワーク使用を必要とするReact Nativeアプリケーションにおいて、優先的なAPIレイヤーとなっています。2025年後半にリリースされたApollo Client 4.0は、モバイル環境向けに特別に設計された、20〜30%小さいバンドルサイズと改善されたTypeScriptサポートを備えた軽量アーキテクチャを提供します。
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プロジェクトの両方で動作します。
# Installation
npm install @apollo/client graphqlクライアントの初期化には、ネットワークリクエスト用のHttpLinkとローカル状態管理用のInMemoryCacheが必要です。
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のレイアウトでルートレベルに配置します。
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型を生成し、実行時の型の不一致を排除します。クライアントプラグインと一緒にインストールします。
# Install codegen tools
npm install -D @graphql-codegen/cli @graphql-codegen/client-presetcodegen設定はスキーマを指定し、出力場所を指定します。
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が導入されています。
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、技術テストで練習しましょう。
ミューテーションと楽観的更新
ミューテーションはサーバーデータを変更し、ローカルキャッシュを更新します。楽観的レスポンスは、サーバーが変更を確認する前に即座のフィードバックを提供します。
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()メソッドにより、型安全なエラー処理が可能になります。
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にシリアライズします。
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プロトコルをサポートしています。
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を使用してすべてのリクエストにトークンを添付することです。
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-MailletSharpSkill 創業者
10 年以上フルスタック開発に携わっています。SharpSkill を運営し、ここで公開される内容に責任を負っています。
2026年8月20日 更新
タグ
共有
関連記事

Flutter vs React Native パフォーマンス比較 2026:ベンチマークと面接対策
Flutter 3.38とReact Native 0.82のパフォーマンスを徹底比較。Impellerエンジン、新アーキテクチャ、フレームレートベンチマーク、メモリ使用量、採用面接で頻出する質問を解説します。

React Native 0.85(2026年):新アニメーションバックエンド、厳格なTypeScript APIと面接対策
React Native 0.85の共有アニメーションバックエンド、ポストブリッジアーキテクチャ、Metro TLSについて、コード例と面接質問を交えて徹底解説します。

React Native 0.84のHermes V1:パフォーマンス最適化、プリコンパイルバイトコード、技術面接対策
Hermes V1がReact Native 0.84のデフォルトJavaScriptエンジンとなり、バイトコードプリコンパイル、Hadesガベージコレクタ、メモリ最適化によって大幅なパフォーマンス向上を実現しました。本記事では技術面接で問われるHermesの内部構造を詳しく解説します。