# React Native and GraphQL in 2026: Apollo Client, Queries and Interview Questions
> Learn to integrate GraphQL with React Native using Apollo Client 4.0. This tutorial covers queries, mutations, caching strategies, and common interview questions about mobile GraphQL development.
- 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 has become the preferred API layer for React Native applications that need flexible data fetching and efficient network usage. Apollo Client 4.0, released in late 2025, brings a leaner architecture with 20-30% smaller bundles and improved TypeScript support specifically designed for mobile environments.
> **Apollo Client 4.0 Key Changes**
>
> Apollo Client 4.0 decouples React-specific exports to `@apollo/client/react`, supports React 19 Suspense and the React Compiler, and replaces the monolithic `ApolloError` with specific error classes for better debugging.
## Setting Up Apollo Client 4 in React Native
The installation process remains straightforward. Apollo Client 4.0 works with both Expo and bare React Native projects.
```bash
# Installation
npm install @apollo/client graphql
```
The client initialization requires an `HttpLink` for network requests and an `InMemoryCache` for local state management.
```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];
},
},
},
},
},
}),
});
```
The `typePolicies` configuration handles cache normalization for paginated data, a common requirement in mobile apps with infinite scroll.
## Wrapping the App with ApolloProvider
The provider pattern connects Apollo Client to the React component tree. Place it at the root level, typically in `App.tsx` or the Expo Router layout.
```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 imports React hooks from `@apollo/client/react` rather than the main entry point. This change reduces bundle size when the core client runs in non-React contexts.
## Writing Type-Safe GraphQL Queries
GraphQL Code Generator produces TypeScript types from the schema, eliminating runtime type mismatches. Install it alongside the client plugin.
```bash
# Install codegen tools
npm install -D @graphql-codegen/cli @graphql-codegen/client-preset
```
The codegen configuration points to the schema and specifies output locations.
```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;
```
Running `npx graphql-codegen` generates typed document nodes that the `useQuery` hook consumes.
## Fetching Data with useQuery
The `useQuery` hook manages loading states, errors, and cache updates. Apollo Client 4.0 introduces the `dataState` API for more predictable state transitions.
```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}
/>
);
}
```
The `cache-and-network` fetch policy displays cached data immediately while refreshing from the server. This pattern reduces perceived latency on mobile networks.
## Mutations and Optimistic Updates
Mutations modify server data and update the local cache. Optimistic responses provide instant feedback before the server confirms the change.
```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 };
}
```
The `cache.modify` method directly updates cached fields without refetching the entire query. This approach minimizes network requests on cellular connections.
## Handling Network Errors in Mobile Apps
Apollo Client 4.0 replaces the generic `ApolloError` with specific error classes. The static `.is()` methods enable type-safe error handling.
```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;
}
```
Distinguishing network errors from GraphQL errors allows different recovery strategies: retry for transient failures, redirect for authentication issues.
## Offline Support with Cache Persistence
Mobile apps need offline access to previously fetched data. The `apollo3-cache-persist` library serializes the cache to 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
});
}
```
Call `initializeCache` before rendering the app to restore cached data from disk. Users see their last-fetched content immediately, even without network access.
## Real-Time Updates with GraphQL Subscriptions
Subscriptions push server events to the client over WebSocket. Apollo Client 4.0 supports the newer [graphql-ws](https://github.com/enisdenjo/graphql-ws) protocol.
```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(),
});
```
The `split` function directs operations to the appropriate transport based on the operation type.
## Common Interview Questions: React Native GraphQL
Technical interviews often probe understanding of GraphQL's mobile-specific tradeoffs. The following questions appear frequently in React Native positions.
### Why choose GraphQL over REST for mobile apps?
GraphQL reduces over-fetching by returning only requested fields. A single query replaces multiple REST endpoints, reducing round trips over high-latency cellular connections. The typed schema enables compile-time validation, catching API mismatches before runtime.
### How does Apollo Client cache data?
Apollo normalizes responses by `__typename` and `id`, storing each entity once. Queries reference normalized objects by cache key. This deduplication saves memory and ensures consistency: updating a product in one list updates it everywhere.
### What fetch policies does Apollo Client support?
| Policy | Behavior | Use Case |
|--------|----------|----------|
| `cache-first` | Return cache if available, else fetch | Default, minimizes requests |
| `cache-and-network` | Return cache immediately, then update from network | Fresh data with instant display |
| `network-only` | Always fetch, update cache | When stale data is unacceptable |
| `cache-only` | Never fetch, fail if not cached | Offline mode |
| `no-cache` | Fetch without caching | Sensitive data |
### How do optimistic updates work?
The client predicts the mutation result and updates the cache before the server responds. If the server returns a different result, Apollo replaces the optimistic data with the actual response. If the mutation fails, Apollo rolls back to the previous state.
### What causes an N+1 problem in GraphQL?
Nested resolvers that fetch related data individually create N+1 queries. Requesting a list of 50 products with their categories triggers 1 product query plus 50 category queries. Server-side DataLoader batches these into a single query.
### How do you handle authentication tokens with Apollo Client?
The recommended approach uses an [Apollo Link](https://www.apollographql.com/docs/react/api/link/introduction/) to attach tokens to every request.
```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}` : '',
},
};
});
```
Chain this link before the `HttpLink` in the client configuration.
## Debugging GraphQL in React Native
Apollo provides multiple debugging options for React Native development. The [VS Code Apollo extension](https://marketplace.visualstudio.com/items?itemName=apollographql.vscode-apollo) includes built-in Client DevTools that display cache contents and query history.
For standalone debugging, Flipper integrates with the community plugin `react-native-apollo-devtools`. This plugin inspects cache state, watches queries in flight, and replays mutations.
Network inspection through React Native Debugger requires enabling "Debug JS Remotely". The Network tab then shows GraphQL payloads with request and response bodies.
## Key Takeaways for Mobile GraphQL Development
- Apollo Client 4.0 reduces bundle size by 20-30% through ESM-first packaging and decoupled React exports.
- The `cache-and-network` fetch policy balances instant display with data freshness on slow connections.
- Optimistic updates provide immediate feedback; `cache.modify` avoids unnecessary refetches.
- Typed error classes in Apollo Client 4.0 enable specific handling for network failures versus GraphQL errors.
- Cache persistence with `apollo3-cache-persist` enables offline access to previously fetched data.
- GraphQL subscriptions require the `graphql-ws` protocol and a split link configuration.
- Interview questions focus on caching strategies, fetch policies, and mobile-specific tradeoffs like N+1 prevention.
---
Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack.
HTML version of this page: https://sharpskill.dev/en/blog/react-native/react-native-graphql-apollo-client-queries-interview