नमस्ते दोस्तों!
स्वागत है The Easy Master पर!
आपने Apollo Server se backend GraphQL API बना ली। Ab frontend ki baari hai – React app mein GraphQL queries aur mutations kaise use karein?
Jab maine pehli baar React mein GraphQL integrate kiya, toh maine socha ki fetch ya axios hi kaafi hai. Lekin jald hi mujhe realise hua – loading states, error handling, caching, optimistic updates – sab kuch manual karna padhta hai. Bohot boilerplate code likhna padhta hai. Tab maine Apollo Client discover kiya – aur life bohot easy ho gayi.
Is Apollo client React Hindi article mein main aapko sikhata hoon:
✅ Apollo Client kya hai – features, caching, ApolloProvider setup
✅ useQuery hook – data fetch karna, loading/error states
✅ useMutation hook – data create/update/delete karna
✅ useLazyQuery & useSubscription hooks – manual fetch aur real-time data
✅ Variables & Fragments – dynamic queries aur reusable fields
✅ Cache Management – normalized cache, fetch policies, cache updates
✅ Pagination – fetchMore se infinite scroll aur “Load More”
✅ Optimistic Updates – instant UI update for better UX
✅ Apollo Client vs URQL vs Relay – kaunsa choose karein
✅ GraphQL Code Generator – TypeScript types autogenerate
✅ Real project example – Pokemon Explorer app with pagination
Chaliye React mein GraphQL queries ka magic implement karte hain! 🚀
Table of Contents
1. Apollo Client Kya Hai? – Features aur Kyun Use Karein
Apollo Client ek comprehensive state management library hai jo JavaScript/React apps mein GraphQL APIs ke saath kaam karta hai. Ye data fetching, caching, aur state management ko handle karta hai – automatically.
Apollo Client is the industry-standard GraphQL client for React applications, providing smart caching, optimistic UI updates, subscriptions, and error handling out of the box.
Key Features:
| Feature | Description |
|---|---|
| Declarative data fetching | Aap sirf query likhte ho, Apollo loading/error states handle karta hai |
| Normalized cache | Results ko type + ID se store karta hai – jab ek entity update hoti hai, saare components automatically update ho jate hain |
| Optimistic UI | Mutation response se pehle UI update kar deta hai – app instant feel hota hai |
| Pagination support | fetchMore hook se easily pagination implement kar sakte ho |
| Devtools | Chrome extension – cache inspect kar sakte ho, queries debug kar sakte ho |
| TypeScript support | Excellent native TypeScript support |
| React Suspense | useSuspenseQuery with Suspense boundaries |
Apollo Client provides a normalized in-memory cache that reduces network requests and makes your app feel extremely fast. Apollo Client 4.1 introduced full @stream directive support, compatibility with the latest GraphQL incremental delivery spec, and powerful new APIs for working with fragments.
2. Apollo Client vs URQL vs Relay – कौनसा Choose करें?
2026 mein GraphQL clients ke liye teen main options hain. Let’s compare:
| Aspect | Apollo Client | URQL | Relay |
|---|---|---|---|
| Bundle size | Larger (~33KB) | Smaller (~23KB) | Large |
| Learning curve | Moderate | Low (minimalistic API) | Steep |
| Cache strategy | Normalized cache (automatic) | Document cache (simpler) | Normalized (graph model) |
| Built-in features | Rich (pagination, subscriptions, optimistic UI) | Minimal (extensible via exchanges) | Powerful but complex |
| React Suspense | ✅ Yes (useSuspenseQuery) | ✅ Yes | ✅ Yes |
| Best for | Large apps, full-featured needs | Small to medium apps, flexibility | Very large apps, strict patterns |
The major difference in urql is that all caching logic is abstracted in exchanges too, which makes it highly customizable.
Apollo Client is a feature-rich GraphQL client, which can lead to a larger bundle size compared to more minimalistic clients. However, its extensive features, including advanced caching and state management, make it suitable for large applications where performance can be optimized through configuration.
Urql focuses on minimalism with built-in caching, SSR support, and React Server Component compatibility. Its small footprint means less overhead for Next.js apps while providing essential features out of the box.
Recommendation for beginners: Start with Apollo Client – sabse zyada tutorials, community support, aur features available hain. For most new projects, choose between @apollo/client (rich ecosystem) and urql (lightweight and flexible).
3. Project Setup – Apollo Client Install Karein
Step 1: Create React App
npm create vite@latest apollo-react-app -- --template react
cd apollo-react-app
npm installStep 2: Install Apollo Client
npm install @apollo/client graphqlStep 3: Install Code Generator (optional but recommended)
npm install -D @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-operations @graphql-codegen/typescript-react-apolloStep 4: Project Structure
text
apollo-react-app/
├── src/
│ ├── main.jsx
│ ├── App.jsx
│ ├── apollo/
│ │ └── client.js
│ └── components/
│ ├── PokemonList.jsx
│ └── PokemonDetail.jsx
├── .env
├── package.json
└── codegen.ts4. ApolloProvider – React App Ko Wrap Karna
ApolloClient instance banakar, ApolloProvider se React app ko wrap karte hain – isse saare components mein client available ho jata hai.
src/apollo/client.js
import { ApolloClient, InMemoryCache, from } from '@apollo/client';
import { onError } from '@apollo/client/link/error';
// Error handling link
const errorLink = onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors) {
graphQLErrors.forEach(({ message, locations, path }) =>
console.log(`[GraphQL error]: Message: ${message}, Path: ${path}`)
);
}
if (networkError) console.log(`[Network error]: ${networkError}`);
});
// Create Apollo Client instance
export const client = new ApolloClient({
uri: import.meta.env.VITE_GRAPHQL_URL || 'https://graphql-pokeapi.graphcdn.app/',
cache: new InMemoryCache({
typePolicies: {
Query: {
fields: {
pokemons: {
keyArgs: false,
merge(existing = { pokemons: [] }, incoming, { args }) {
// Custom pagination merge logic
const offset = args?.offset || 0;
const merged = existing.pokemons ? [...existing.pokemons] : [];
for (let i = 0; i < incoming.pokemons.length; ++i) {
merged[offset + i] = incoming.pokemons[i];
}
return { ...incoming, pokemons: merged };
},
},
},
},
},
}),
defaultOptions: {
watchQuery: {
fetchPolicy: 'cache-and-network',
errorPolicy: 'all',
},
query: {
fetchPolicy: 'network-only',
errorPolicy: 'all',
},
},
connectToDevTools: true,
});src/main.jsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { ApolloProvider } from '@apollo/client';
import { client } from './apollo/client';
import App from './App';
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<ApolloProvider client={client}>
<App />
</ApolloProvider>
</React.StrictMode>
);ApolloProvider apne child components mein ApolloClient inject kar deta hai – isliye aap kisi भी component mein useQuery, useMutation hooks use kar sakte ho without passing client manually.
5. useQuery Hook – Data Fetch Karne Ka Sahi Tarika
useQuery Apollo Client ka sabse commonly used hook hai – data fetch karne ke liye. Ye automatic loading, error, aur data states provide karta hai.
5.1 Basic Query Example
graphql
# GraphQL query (define outside component to avoid recreation)
const GET_POKEMONS = gql`
query GetPokemons($limit: Int!, $offset: Int!) {
pokemons(limit: $limit, offset: $offset) {
count
nextOffset
results {
id
name
image
}
}
}
`;Component:
import { useQuery, gql } from '@apollo/client';
function PokemonList() {
const { loading, error, data, fetchMore, refetch } = useQuery(GET_POKEMONS, {
variables: { limit: 20, offset: 0 },
notifyOnNetworkStatusChange: true,
});
if (loading) return <div>Loading Pokemons...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div>
<button onClick={() => refetch()}>Refresh</button>
<ul>
{data.pokemons.results.map(pokemon => (
<li key={pokemon.id}>
<img src={pokemon.image} alt={pokemon.name} width="96" />
<h3>{pokemon.name}</h3>
</li>
))}
</ul>
</div>
);
}5.2 Loading, Error, Data States
| State | When | What to do |
|---|---|---|
loading: true | Query पहली बार चल रही है | Loading spinner dikhao |
error | Network ya GraphQL error aaya hai | Error message dikhao |
data | Query successful, data available | UI render karo |
5.3 Polling & Refetching
Polling (regular intervals):
const { data, loading, error } = useQuery(GET_DATA, {
pollInterval: 5000, // har 5 seconds mein refetch
});Manual refetch:
const { refetch } = useQuery(GET_DATA);
<button onClick={() => refetch({ limit: 50 })}>Load 50 items</button>5.4 useSuspenseQuery – React Suspense Integration
Apollo Client v3.13.0 introduced useSuspenseQuery hook, which suspends rendering until data is fully loaded – perfect for React Suspense boundaries.
import { Suspense } from 'react';
import { useSuspenseQuery } from '@apollo/client';
function PokemonListWithSuspense() {
const { data } = useSuspenseQuery(GET_POKEMONS, {
variables: { limit: 20, offset: 0 },
});
return <PokemonCards pokemons={data.pokemons.results} />;
}
// Parent component
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<PokemonListWithSuspense />
</Suspense>
);
}6. useMutation Hook – Data Modify Karna
useMutation hook GraphQL mutations run karne ke liye hota hai – data create, update, delete karne ke liye.
6.1 Basic Mutation Example
graphql
const ADD_POKEMON = gql`
mutation AddPokemon($name: String!, $image: String!) {
addPokemon(name: $name, image: $image) {
id
name
image
}
}
`;Component:
import { useMutation, gql } from '@apollo/client';
function AddPokemonForm() {
const [addPokemon, { loading, error, data }] = useMutation(ADD_POKEMON);
const handleSubmit = async (e) => {
e.preventDefault();
const formData = new FormData(e.target);
try {
const result = await addPokemon({
variables: {
name: formData.get('name'),
image: formData.get('image'),
},
});
console.log('Pokemon added:', result.data.addPokemon);
e.target.reset();
} catch (err) {
console.error('Mutation error:', err);
}
};
return (
<form onSubmit={handleSubmit}>
<input name="name" placeholder="Pokemon name" required />
<input name="image" placeholder="Image URL" required />
<button type="submit" disabled={loading}>
{loading ? 'Adding...' : 'Add Pokemon'}
</button>
{error && <p>Error: {error.message}</p>}
{data && <p>Successfully added {data.addPokemon.name}!</p>}
</form>
);
}6.2 UI Update – Refetch Queries
Mutation ke baad UI update karne ke do main tarike hain:
Method 1: refetchQueries (simple but extra network call)
const [addPokemon] = useMutation(ADD_POKEMON, {
refetchQueries: [
{ query: GET_POKEMONS, variables: { limit: 20, offset: 0 } },
'GetPokemonCount', // if query has a name
],
});Method 2: update function (manual cache update)
const [addPokemon] = useMutation(ADD_POKEMON, {
update(cache, { data: { addPokemon } }) {
// Read existing cached data
const existingData = cache.readQuery({
query: GET_POKEMONS,
variables: { limit: 20, offset: 0 },
});
// Write updated data back to cache
cache.writeQuery({
query: GET_POKEMONS,
variables: { limit: 20, offset: 0 },
data: {
pokemons: {
...existingData.pokemons,
results: [addPokemon, ...existingData.pokemons.results],
},
},
});
},
});6.3 Optimistic Updates
Optimistic UI mutation response se pehle hi UI update kar deta hai – app instant feel hota hai.
const [addPokemon] = useMutation(ADD_POKEMON, {
optimisticResponse: {
addPokemon: {
__typename: 'Pokemon',
id: `temp-${Date.now()}`,
name: optimisticName,
image: optimisticImage,
},
},
update(cache, { data: { addPokemon } }) {
// update cache with real data when response arrives
},
});Apollo Client provides optimistic UI capabilities that update your UI immediately while waiting for the server response, providing a smoother user experience.
7. useLazyQuery & useSubscription – Advanced Hooks
7.1 useLazyQuery – Manual Execution
useLazyQuery query को manually trigger karne ke liye hota hai – button click par या scroll event par।
import { useLazyQuery, gql } from '@apollo/client';
const GET_POKEMON_DETAIL = gql`
query GetPokemonDetail($name: String!) {
pokemon(name: $name) {
id
name
height
weight
abilities
}
}
`;
function PokemonSearch() {
const [searchTerm, setSearchTerm] = useState('');
const [getPokemon, { loading, error, data }] = useLazyQuery(GET_POKEMON_DETAIL);
const handleSearch = () => {
if (searchTerm) {
getPokemon({ variables: { name: searchTerm.toLowerCase() } });
}
};
return (
<div>
<input
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
placeholder="Enter Pokemon name"
/>
<button onClick={handleSearch} disabled={loading}>Search</button>
{loading && <p>Loading...</p>}
{error && <p>Error: {error.message}</p>}
{data && (
<div>
<h2>{data.pokemon.name}</h2>
<p>Height: {data.pokemon.height}, Weight: {data.pokemon.weight}</p>
</div>
)}
</div>
);
}7.2 useSubscription – Real-time Data
Subscriptions real-time data ke liye hote hain – chat, notifications, live updates।
import { useSubscription, gql } from '@apollo/client';
const POKEMON_ADDED_SUBSCRIPTION = gql`
subscription OnPokemonAdded {
pokemonAdded {
id
name
image
}
}
`;
function PokemonLiveFeed() {
const { data, loading } = useSubscription(POKEMON_ADDED_SUBSCRIPTION);
if (loading) return <p>Connecting to live feed...</p>;
return (
<div>
<h3>New Pokemon Added:</h3>
{data && (
<div>
<img src={data.pokemonAdded.image} width="64" />
<p>{data.pokemonAdded.name}</p>
</div>
)}
</div>
);
}8. Variables & Fragments – Dynamic aur Reusable Queries
8.1 Variables in Queries
Variables queries ko dynamic aur reusable banate hain।
const GET_POKEMONS = gql`
query GetPokemons($limit: Int!, $offset: Int!) {
pokemons(limit: $limit, offset: $offset) {
count
nextOffset
results {
id
name
image
}
}
}
`;
// In component
const { data, fetchMore } = useQuery(GET_POKEMONS, {
variables: { limit: 20, offset: 0 },
});8.2 Fragments – Reusable Field Sets
Fragments fields ke reusable sets hote hain – same fields multiple queries mein use karna ho to fragment banao।
Fragment definition:
graphql
fragment PokemonCardFields on Pokemon {
id
name
image
types
}Query mein fragment ka use:
const GET_POKEMONS = gql`
${POKEMON_CARD_FRAGMENT}
query GetPokemons($limit: Int!, $offset: Int!) {
pokemons(limit: $limit, offset: $offset) {
count
results {
...PokemonCardFields
}
}
}
`;
// Fragment component mein collocate karo
const POKEMON_CARD_FRAGMENT = gql`
fragment PokemonCardFields on Pokemon {
id
name
image
types
}
`;9. Cache Management – Apollo Client Ka Superpower
Apollo Client ka normalized cache iski superpower hai। Ye results ko __typename और id ke basis pe store karta hai – jab ek entity update hoti hai, toh saare components jahaan woh entity use hoti hai automatically update ho jate hain।
9.1 Fetch Policies
fetchPolicy decide karta hai ki query cache se data le ya network se:
| Policy | Behavior |
|---|---|
cache-first (default) | Cache mein hai to cache se le, otherwise network |
network-only | Always fetch from network, update cache |
cache-and-network | Cache se serve karo, then network se fetch karo and update |
no-cache | Cache use mat karo (read/write both) |
cache-only | Sirf cache se read karo, network call mat karo |
const { data } = useQuery(GET_POKEMONS, {
fetchPolicy: 'cache-and-network',
variables: { limit: 20, offset: 0 },
});Apollo Client 4.1 introduces new prioritizeCacheValues flag in fetch policies。
9.2 Cache Normalization
When any component fetches a user, every other component showing that user updates automatically. Normalized caching means pokemon:1 stored once and reused across components.
10. Pagination – FetchMore & Field Policies
Pagination large datasets efficiently handle karne ke liye essential hai। Apollo Client fetchMore function provide karta hai।
Basic Pagination with fetchMore
function PokemonListWithPagination() {
const { loading, error, data, fetchMore } = useQuery(GET_POKEMONS, {
variables: { limit: 20, offset: 0 },
});
const loadMore = () => {
fetchMore({
variables: {
offset: data.pokemons.results.length,
},
updateQuery: (prevResult, { fetchMoreResult }) => {
if (!fetchMoreResult) return prevResult;
return {
pokemons: {
...fetchMoreResult.pokemons,
results: [
...prevResult.pokemons.results,
...fetchMoreResult.pokemons.results,
],
},
};
},
});
};
if (loading && !data) return <div>Loading...</div>;
if (error) return <div>Error!</div>;
return (
<div>
<PokemonGrid pokemons={data.pokemons.results} />
{data.pokemons.nextOffset && (
<button onClick={loadMore}>Load More</button>
)}
</div>
);
}Advanced: Field Policy for Infinite Scroll
You can also configure pagination via typePolicies in InMemoryCache – as shown earlier in client setup。
Caching paginated queries has always been a bit tricky, and required a lot of manual work to merge the results。 With Apollo Client’s type policies, Relay-style pagination is supported out of the box, and the cache will take care of merging the results for you。
11. GraphQL Code Generator – TypeScript Types Autogenerate
GraphQL Code Generator ek tool hai jo aapke GraphQL schema aur operations se TypeScript types, typed hooks, aur full SDK clients autogenerate kar detा है – build time par। यह schema aur resolver changes ko type-safe detect karne में मदद करता है।
Installation
npm install -D @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-operations @graphql-codegen/typescript-react-apollocodegen.ts Configuration
import type { CodegenConfig } from '@graphql-codegen/cli';
const config: CodegenConfig = {
schema: 'https://graphql-pokeapi.graphcdn.app/',
documents: ['src/**/*.tsx', 'src/**/*.graphql'],
generates: {
'./src/generated/graphql.ts': {
plugins: [
'typescript',
'typescript-operations',
'typescript-react-apollo',
],
config: {
withHooks: true,
withRefetchFn: true,
},
},
},
};
export default config;package.json Scripts
"scripts": {
"codegen": "graphql-codegen --config codegen.ts",
"dev": "npm run codegen && vite"
}Generated Hooks Ka Use
import { useGetPokemonsQuery } from '../generated/graphql';
function PokemonList() {
const { data, loading, error, fetchMore } = useGetPokemonsQuery({
variables: { limit: 20, offset: 0 },
});
// data is fully typed!
return <div>{data?.pokemons?.results.map(p => <div key={p.id}>{p.name}</div>)}</div>;
}12. Error Handling – Network aur GraphQL Errors
Apollo Client errors ke liye do categories provide karta hai:
| Error Type | When | Example |
|---|---|---|
| Network error | Server reachable nahi hai, network down, CORS issue | Failed to fetch |
| GraphQL error | Query syntax wrong, resolver error, validation failed | Cannot query field "xyz" on type "Pokemon" |
Comprehensive Error Handling
import { ApolloError } from '@apollo/client';
function ErrorDisplay({ error }: { error: ApolloError }) {
if (error.networkError) {
return (
<div className="error network-error">
<h3>Network Error</h3>
<p>Unable to connect to server. Please check your internet connection.</p>
<button onClick={() => window.location.reload()}>Retry</button>
</div>
);
}
if (error.graphQLErrors?.length) {
return (
<div className="error graphql-error">
<h3>GraphQL Error</h3>
<ul>
{error.graphQLErrors.map((err, idx) => (
<li key={idx}>
{err.message} {err.extensions?.code && `(Code: ${err.extensions.code})`}
</li>
))}
</ul>
</div>
);
}
return <div className="error">An unexpected error occurred: {error.message}</div>;
}Client-wide Error Handling via onError Link
import { onError } from '@apollo/client/link/error';
const errorLink = onError(({ graphQLErrors, networkError, operation, forward }) => {
if (graphQLErrors) {
for (let err of graphQLErrors) {
console.log(`[GraphQL error]: Message: ${err.message}, Path: ${err.path}`);
if (err.extensions?.code === 'UNAUTHENTICATED') {
// Redirect to login
window.location.href = '/login';
}
}
}
if (networkError) {
console.log(`[Network error]: ${networkError}`);
// Show toast notification to user
}
});13. Best Practices – Production-Level Tips
✅ Use fragments for field consistency – Same fields multiple queries mein reuse karo। Fragment collocation pattern use karo – fragment ko us component ke saath define karo jo use karta hai।
✅ Use GraphQL Code Generator – TypeScript types aur hooks autogenerate karo। Isse compile time pe errors catch ho jate hain and development experience improve hota hai।
✅ Use fetch policy cache-and-network for frequently updated data – Cache se pehle dikhao, background mein update karo।
✅ Implement optimistic updates for mutations – Instant UI feedback, better UX।
✅ Use update function over refetchQueries when possible – Extra network calls avoid karo। Manual cache update is more efficient。
✅ Name your queries and mutations – useGetPokemonsQuery (generated), debugging easier hota hai। Apollo Devtools mein named operations show hote hain।
✅ Implement error boundaries – Handle GraphQL and network errors gracefully。
✅ Use useLazyQuery for user-triggered fetches – Search, filter, pagination actions।
✅ Set reasonable pollInterval for real-time data – Avoid polling when not needed。 Use useSubscription for true real-time。
✅ Test components with MockedProvider – No need for live GraphQL server in tests。
💡 Personal Experience: Jab maine pehli baar Apollo Client use kiya tha, maine har mutation ke baad
refetchQueriesuse kiya – jisse extra network calls hote the। Baad meinupdatefunction auroptimisticResponseuse karke maine network calls 50% kam kar diye aur UI instantly responsive ban gaya। Optimistic updates is a game-changer for UX!
14. Real Project Example – Pokemon Explorer App
Chaliye sab concepts ko combine karte hain – ek fully functional Pokemon Explorer App banate hain with pagination, search, and details.
Project Structure
text
pokemon-explorer/
├── src/
│ ├── main.jsx
│ ├── App.jsx
│ ├── apollo/client.js
│ ├── components/
│ │ ├── PokemonList.jsx
│ │ ├── PokemonCard.jsx
│ │ ├── PokemonDetail.jsx
│ │ ├── SearchBar.jsx
│ │ └── LoadingSpinner.jsx
│ ├── hooks/
│ │ └── usePokemonSearch.js
│ ├── graphql/
│ │ ├── queries.graphql
│ │ ├── fragments.graphql
│ │ └── mutations.graphql
│ └── generated/
│ └── graphql.ts
├── codegen.ts
├── .env
└── package.jsonFragments (src/graphql/fragments.graphql)
graphql
fragment PokemonCard on Pokemon {
id
name
image
types
}
fragment PokemonDetails on Pokemon {
...PokemonCard
height
weight
abilities
baseExperience
stats {
name
value
}
}Queries (src/graphql/queries.graphql)
graphql
query GetPokemons($limit: Int!, $offset: Int!) {
pokemons(limit: $limit, offset: $offset) {
count
nextOffset
results {
...PokemonCard
}
}
}
query GetPokemonDetail($name: String!) {
pokemon(name: $name) {
...PokemonDetails
}
}
query SearchPokemons($search: String!) {
searchPokemons(search: $search) {
...PokemonCard
}
}Apollo Client Setup (src/apollo/client.js)
import { ApolloClient, InMemoryCache, from } from '@apollo/client';
import { onError } from '@apollo/client/link/error';
const errorLink = onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors) {
graphQLErrors.forEach(({ message, path }) =>
console.error(`[GraphQL error]: Message: ${message}, Path: ${path}`)
);
}
if (networkError) console.error(`[Network error]: ${networkError}`);
});
export const client = new ApolloClient({
uri: import.meta.env.VITE_GRAPHQL_URL || 'https://graphql-pokeapi.graphcdn.app/',
cache: new InMemoryCache({
typePolicies: {
Query: {
fields: {
pokemons: {
keyArgs: false,
merge(existing = { results: [] }, incoming, { args }) {
const offset = args?.offset || 0;
const results = existing.results ? [...existing.results] : [];
for (let i = 0; i < incoming.results.length; ++i) {
results[offset + i] = incoming.results[i];
}
return { ...incoming, results };
},
},
},
},
},
}),
link: from([errorLink]),
connectToDevTools: true,
});PokemonList Component (src/components/PokemonList.jsx)
import { useQuery, gql } from '@apollo/client';
import PokemonCard from './PokemonCard';
import LoadingSpinner from './LoadingSpinner';
const GET_POKEMONS = gql`
query GetPokemons($limit: Int!, $offset: Int!) {
pokemons(limit: $limit, offset: $offset) {
count
nextOffset
results {
id
name
image
types
}
}
}
`;
function PokemonList() {
const { loading, error, data, fetchMore } = useQuery(GET_POKEMONS, {
variables: { limit: 20, offset: 0 },
notifyOnNetworkStatusChange: true,
});
const loadMore = () => {
fetchMore({
variables: { offset: data.pokemons.results.length },
updateQuery: (prev, { fetchMoreResult }) => {
if (!fetchMoreResult) return prev;
return {
pokemons: {
...fetchMoreResult.pokemons,
results: [...prev.pokemons.results, ...fetchMoreResult.pokemons.results],
},
};
},
});
};
if (loading && !data) return <LoadingSpinner />;
if (error) return <div>Error: {error.message}</div>;
return (
<div>
<div className="pokemon-grid">
{data.pokemons.results.map((pokemon) => (
<PokemonCard key={pokemon.id} pokemon={pokemon} />
))}
</div>
{data.pokemons.nextOffset && (
<button onClick={loadMore} disabled={loading} className="load-more-btn">
{loading ? 'Loading...' : 'Load More'}
</button>
)}
</div>
);
}
export default PokemonList;PokemonDetail Component (src/components/PokemonDetail.jsx)
import { useQuery, gql } from '@apollo/client';
import { useParams } from 'react-router-dom';
const GET_POKEMON_DETAIL = gql`
query GetPokemonDetail($name: String!) {
pokemon(name: $name) {
id
name
image
types
height
weight
abilities
baseExperience
stats {
name
value
}
}
}
`;
function PokemonDetail() {
const { name } = useParams();
const { loading, error, data } = useQuery(GET_POKEMON_DETAIL, {
variables: { name: name.toLowerCase() },
});
if (loading) return <LoadingSpinner />;
if (error) return <div>Error loading {name}: {error.message}</div>;
const pokemon = data.pokemon;
return (
<div className="pokemon-detail">
<img src={pokemon.image} alt={pokemon.name} />
<h1>{pokemon.name}</h1>
<div className="types">
{pokemon.types.map(type => <span key={type} className={`type type-${type}`}>{type}</span>)}
</div>
<div className="stats">
<p>Height: {pokemon.height} dm</p>
<p>Weight: {pokemon.weight} hg</p>
<p>Base Experience: {pokemon.baseExperience}</p>
</div>
<div className="abilities">
<h3>Abilities</h3>
<ul>{pokemon.abilities.map(ability => <li key={ability}>{ability}</li>)}</ul>
</div>
<div className="stat-bars">
<h3>Stats</h3>
{pokemon.stats.map(stat => (
<div key={stat.name}>
<label>{stat.name}: {stat.value}</label>
<progress value={stat.value} max="255" />
</div>
))}
</div>
</div>
);
}App Component (src/App.jsx)
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';
import PokemonList from './components/PokemonList';
import PokemonDetail from './components/PokemonDetail';
function App() {
return (
<BrowserRouter>
<div className="app">
<header>
<Link to="/">
<h1>Pokémon Explorer</h1>
</Link>
</header>
<main>
<Routes>
<Route path="/" element={<PokemonList />} />
<Route path="/pokemon/:name" element={<PokemonDetail />} />
</Routes>
</main>
</div>
</BrowserRouter>
);
}
export default App;15. Resources – Cheat Sheet & Practice Prompts
Apollo Client Hooks Cheat Sheet
| Hook | Purpose | Example |
|---|---|---|
useQuery | Fetch data, automatic loading/error states | const { data, loading, error } = useQuery(GET_DATA) |
useLazyQuery | Manually trigger query | const [getData, { data }] = useLazyQuery(GET_DATA) |
useMutation | Create/update/delete data | const [mutate] = useMutation(CREATE_DATA) |
useSubscription | Real-time data over WebSocket | const { data } = useSubscription(NEW_DATA_SUB) |
useApolloClient | Access client instance | const client = useApolloClient() |
Apollo Client Setup Cheat Sheet
// Setup
import { ApolloClient, InMemoryCache, ApolloProvider } from '@apollo/client';
const client = new ApolloClient({
uri: 'https://api.example.com/graphql',
cache: new InMemoryCache(),
});
// Wrap app
<ApolloProvider client={client}>
<App />
</ApolloProvider>Codegen Config Cheat Sheet (codegen.ts)
import type { CodegenConfig } from '@graphql-codegen/cli';
const config: CodegenConfig = {
schema: 'https://your-api.com/graphql',
documents: ['src/**/*.tsx', 'src/**/*.graphql'],
generates: {
'./src/generated/graphql.ts': {
plugins: ['typescript', 'typescript-operations', 'typescript-react-apollo'],
},
},
};Practice Prompts
Beginner:
- Apollo Client setup karo, public GraphQL API use karo (e.g., Pokemon API)।
useQueryse list fetch karo aur display karo with loading/error states。
Intermediate:
- Add mutation for adding new item (if API supports) or implement search functionality। Use
useLazyQueryfor search। Use fragments to reuse field definitions across queries।
Advanced:
- Implement pagination with
fetchMoreand infinite scroll। Add optimistic updates for mutations। Implement error boundaries。 Set up GraphQL Code Generator with TypeScript and verify type safety。
16. FAQ
Q1: Apollo Client aur plain fetch mein kya antar hai?
Apollo Client provides normalized caching, optimistic updates, loading/error states, request batching, and automatic UI updates – sab out of the box। Plain fetch mein sab kuch manually karna padta hai।
Q2: useQuery aur useLazyQuery mein kya antar hai?
useQuery automatically runs when component mounts। useLazyQuery returns a function that you call manually – useful for search, button clicks, etc।
Q3: Mutation ke baad UI kaise update karein?
Three ways: (1) refetchQueries – simple but extra network call, (2) update function – manual cache update, no extra call, (3) Return updated object and let Apollo automatically update cache for normalized types।
Q4: Apollo Client caching kaise work karta hai?
Apollo Client stores results in a normalized in-memory cache using __typename and id fields। When you fetch a pokemon:1, it’s stored once। If another component queries the same pokemon, cache serves it immediately।
Q5: GraphQL Code Generator kyun use karein?
Code generator reads your GraphQL schema and operations, then generates TypeScript types, typed hooks, and even full SDK clients – all at build time। Isse compile-time errors catch ho jate hain और development experience type-safe ho jata hai।
Q6: Apollo Client development aur production mein kaise configure karein?
Use environment variables for API URLs। Set connectToDevTools: process.env.NODE_ENV !== 'production'। Use different fetch policies for development vs production (e.g., cache-and-network for dev, cache-first for prod)।
17. Conclusion – Ab Aapki Baari!
Bahut badhiya! Aapne aaj seekh liya:
✅ Apollo client React Hindi – complete frontend integration guide
✅ Apollo Client setup – ApolloProvider, InMemoryCache, environment config
✅ useQuery – data fetch, loading/error states, polling, refetching
✅ useMutation – data modify, refetchQueries, cache update, optimistic updates
✅ useLazyQuery & useSubscription – manual fetch aur real-time data
✅ Variables & Fragments – dynamic queries aur reusable fields
✅ Cache Management – normalized cache, fetch policies, type policies
✅ Pagination – fetchMore with infinite scroll and field policies
✅ GraphQL Code Generator – TypeScript types autogenerate
✅ Error handling – network and GraphQL errors
✅ Best practices – production-level tips
✅ Real project – Pokemon Explorer App
Apollo Client React apps mein GraphQL ko seamless banata है – caching, optimistic updates, error handling – sab built-in। Ab aap production-grade GraphQL frontends bana sakte ho।
Aapki challenge: Pokemon Explorer app implement karo (or any public GraphQL API)。 Pagination, search, and details page implement karo। Add optimistic updates for any mutation (if API supports)。 TypeScript + GraphQL Code Generator setup karo। Apna experience comment mein share karo!
Next topic kya chahiye?
- GraphQL Subscriptions (Real-time chat with React + Apollo)?
- GraphQL Federation (Multiple GraphQL services)?
- Apollo Client + Next.js (Server-side rendering)?
Comment mein batao!
The Easy Master ke saath Apollo Client seekhte raho। Happy coding! 🚀🔷
Resources
- Apollo Client React Official Docs
- Apollo Client Hooks API Reference
- GraphQL Code Generator with React
- URQL – Lightweight GraphQL Client
- Pokémon GraphQL API
Additional Resources
- MongoDB Setup – CRUD Operations समझे (Beginner Guide) 2026
- MongoDB Compass से GUI Database Manage करने का आसान तरीका | Beginner Tutorial 2026
- Node.js MongoDB Connection – Mongoose Setup समझे 2026
- MongoDB Data Modeling – Embedded Documents vs References 2026
- MongoDB Indexing – Query Speed बढ़ने करने का आसान तरीका
- MongoDB Aggregation Pipeline – Stages समझे | Practical Examples
- Express MongoDB CRUD – Complete REST API Example
- Mongoose ODM – Schema, Model, and Validation समझे 2026
- MongoDB Atlas – Cloud Database Free में Deploy करें 2026
- JWT Authentication MongoDB – User Login System कैसे बनाएं 2026
- Next.js App Router – Pages Router से क्या बदला? Complete Guide 2026
- Next.js Server Components – ‘use client’ कब और कहां Use करें
- Next.js Routing – Layouts, Dynamic Routes and Nested Routes 2026
- Next.js 16 New Features – Turbopack, Cache Components and proxy.ts
- Next.js Partial Prerendering – Static and Dynamic Content साथ में
- Next.js Authentication – JWT Session Management (App Router) 2026
- Next.js SEO – Metadata API and Image Optimization समझे 2026
- Next.js TypeScript – Full-Stack Type-Safe App कैसे बनाएं
- FastAPI Kya Hai? FastAPI Python Setup Aur Pehla API Hindi 2026
- FastAPI Path Parameters Hindi – शून्य से हीरो तक गाइड 2026
- Pydantic v2 Tutorial Hindi – Data Validation Master 2026
- FastAPI dependency injection Hindi – Code Reuse Ka Magic
- FastAPI Async Await Hindi – Non-Blocking Code 2026
- FastAPI PostgreSQL SQLModel Hindi – Async Guide 2026
- FastAPI JWT Authentication Hindi – Secure API Login
- FastAPI OpenAI Integration Hindi – AI Chatbot API 2026
- FastAPI Multi-Agent AI Hindi – LangGraph Zero to Hero
- FastAPI Deployment Hindi – Railway Zero to Hero 2026
- Docker Introduction in Hindi? Containers vs Virtual Machines
- Docker Images and Containers Hindi – Pehla Container
- Docker Compose Tutorial Hindi – Node.js + MongoDB
- Docker Volumes Networking Hindi – Data Persist कैसे करें
- Kubernetes Architecture Hindi – Pods, Nodes, Cluster
- Minikube Tutorial Hindi – Local Cluster कैसे बनाए
- Kubernetes Deployments Services Hindi – App Expose Karein
- K8s Ingress Tutorial Hindi – Domain se App Access
- Helm Kya Hai? – Kubernetes Charts Se App Deploy
- GraphQL Introduction in Hindi – REST vs GraphQL Comparison
- GraphQL Schema Tutorial Hindi – Types Queries Resolvers
- GraphQL Queries Mutations Hindi – Frontend Integration
- GraphQL Advanced Features Hindi – Fragments Aliases Variables
- Apollo Server GraphQL Node.js TypeScript Hindi – API Kaise Banaye
Views: 357