ככל שהפרויקט שלך גדל, מספר שאילתות ה-GraphQL מתרבה—ובעיית N+1 וחוסר הסנכרון של המטמון הופכים לכאב ראש אמיתי. ראינו קוד שבו כל קומפוננטה מריצה import { ApolloClient, InMemoryCache, createHttpLink, from, split, ApolloLink } from '@apollo/client' import { setContext } from '@apollo/client/link/context' import { onError } from '@apollo/client/link/error' import { GraphQLWsLink } from '@apollo/client/link/subscriptions' import { createClient as createWsClient } from 'graphql-ws' import { getMainDefinition } from '@apollo/client/utilities' const httpLink = createHttpLink({ uri: import.meta.env.VITE_GRAPHQL_URL ?? '/graphql' }) const authLink = setContext((_, { headers }) => { const token = localStorage.getItem('token') return { headers: { ...headers, ...(token ? { authorization: `Bearer ${token}` } : {}) } } }) const errorLink = onError(({ graphQLErrors, networkError }) => { graphQLErrors?.forEach(({ message, extensions }) => { if (extensions?.code === 'UNAUTHENTICATED') { /* logout */ } }) }) const wsLink = new GraphQLWsLink(createWsClient({ url: import.meta.env.VITE_GRAPHQL_WS_URL, connectionParams: { authorization: `Bearer ${localStorage.getItem('token')}` } })) const splitLink = split( ({ query }) => getMainDefinition(query).operation === 'subscription', wsLink, from([errorLink, authLink, httpLink]) ) export const client = new ApolloClient({ link: splitLink, cache: new InMemoryCache({ typePolicies: { Query: { fields: { products: { keyArgs: ['categoryId'], merge(existing, incoming, { args }) { return args?.offset ? { ...incoming, items: [...(existing?.items ?? []), ...incoming.items] } : incoming } } } } } }), defaultOptions: { watchQuery: { fetchPolicy: 'cache-and-network', errorPolicy: 'all' }, query: { fetchPolicy: 'network-only', errorPolicy: 'all' } } }) משלה, ובמוטציה צריך לאפס את המטמון ידנית. בפרויקט מסחר אלקטרוני עם 50,000 מוצרים, כל קומפוננטת קטלוג ביצעה IntrospectionFragmentMatcher משלה, מה שגרם ל-N+1 ולהאטות. לאחר הגדרת Apollo Client עם possibleTypes, עומס ה-API ירד ב-40%.
Apollo Client עם possibleTypes מנורמל פותר את זה: הוא מעדכן אוטומטית את כל הקומפוננטות הרשומות לישויות שהשתנו. במשך 5 שנים, יישמנו אותו ביותר מ-15 פרויקטים—מחנויות מקוונות ועד לוחות מחוונים בזמן אמת. לפי תיעוד Apollo Client, שימוש במטמון מנורמל מפחית עדכונים ידניים ב-30%.
להלן מדריך הגדרה קונקרטי: מהגדרת הלקוח ועד ליצירת קוד ואופטימיזציה של המטמון. בלי שטויות—רק תצורות ותבניות שעובדות.
למה Apollo Client עדיף על urql לפרויקטים מורכבים?
| קריטריון | Apollo Client | urql | Relay |
|---|---|---|---|
| מטמון מנורמל | כן, InMemoryCache | כן, מטמון מסמכים | כן |
| מינויים (Subscriptions) | כן | כן | באמצעות subscriptions-transport-ws |
| גודל (min+gzip) | ~34 KB | ~15 KB | ~45 KB |
| פופולריות (npm/שבוע) | 2.5M+ | 500K+ | 400K+ |
| אינטגרציית React | Hooks + HOC | Hooks | מודל Fragment |
Apollo Client פופולרי פי 5 מ-urql לפי הורדות npm ומספק ערכת כלים בוגרת יותר. למוצרים עם עשרות קשרים הדדיים, מטמון מנורמל הוא יתרון קריטי: הוא חוסך עד 30% מזמן הפיתוח כי אין צורך לכתוב עדכונים ידניים. בנוסף, Apollo מבצע דה-דופליקציה אוטומטית של שאילתות זהות, מה שמפחית את עומס השרת באפליקציות עם תעבורה גבוהה—ל-urql אין תכונה זו.
איך להגדיר נכון את Apollo Client?
התקנה והגדרת הלקוח
התקן חבילות וצור לקוח עם קישורי HTTP ו-WebSocket, אימות וטיפול בשגיאות. האלמנט המרכזי הוא @graphql-codegen/fragment-matcher עם update עבור פגינציה:
import { ApolloClient, InMemoryCache, createHttpLink, from, split, ApolloLink } from '@apollo/client'
import { setContext } from '@apollo/client/link/context'
import { onError } from '@apollo/client/link/error'
import { GraphQLWsLink } from '@apollo/client/link/subscriptions'
import { createClient as createWsClient } from 'graphql-ws'
import { getMainDefinition } from '@apollo/client/utilities'
const httpLink = createHttpLink({
uri: import.meta.env.VITE_GRAPHQL_URL ?? '/graphql'
})
const authLink = setContext((_, { headers }) => {
const token = localStorage.getItem('token')
return {
headers: {
...headers,
...(token ? { authorization: `Bearer ${token}` } : {})
}
}
})
const errorLink = onError(({ graphQLErrors, networkError }) => {
graphQLErrors?.forEach(({ message, extensions }) => {
if (extensions?.code === 'UNAUTHENTICATED') {
/* logout */
}
})
})
const wsLink = new GraphQLWsLink(createWsClient({
url: import.meta.env.VITE_GRAPHQL_WS_URL,
connectionParams: {
authorization: `Bearer ${localStorage.getItem('token')}`
}
}))
const splitLink = split(
({ query }) => getMainDefinition(query).operation === 'subscription',
wsLink,
from([errorLink, authLink, httpLink])
)
export const client = new ApolloClient({
link: splitLink,
cache: new InMemoryCache({
typePolicies: {
Query: {
fields: {
products: {
keyArgs: ['categoryId'],
merge(existing, incoming, { args }) {
return args?.offset ? { ...incoming, items: [...(existing?.items ?? []), ...incoming.items] } : incoming
}
}
}
}
}
}),
defaultOptions: {
watchQuery: {
fetchPolicy: 'cache-and-network',
errorPolicy: 'all'
},
query: {
fetchPolicy: 'network-only',
errorPolicy: 'all'
}
}
}) Fragment matcher עבור fragment של ממשקים
אם הסכמה שלך משתמשת בממשקים או בטיפוסי union, הגדר useMutation או optimisticResponse במטמון. אחרת Apollo לא ינרמל fragment, והמטמון יתאפס בכל בקשה. צור @graphql-codegen אוטומטית עם npm install -D @graphql-codegen/cli @graphql-codegen/client-preset npx graphql-codegen init .
עדכונים אופטימיים
Apollo Client תומך בעדכונים אופטימיים: אתה יכול לעדכן את ממשק המשתמש באופן מיידי בזמן שבקשת השרת מתבצעת. הגדר את פונקציית codegen.ts ב-import type { CodegenConfig } from '@graphql-codegen/cli' const config: CodegenConfig = { overwrite: true, schema: 'http://localhost:4000/graphql', documents: 'src/**/*.graphql', generates: { 'src/gql/': { preset: 'client', config: { useTypeImports: true, strictScalars: true, scalars: { DateTime: 'string', UUID: 'string' } } } } } export default config והעבר npx graphql-codegen --watch. זה מפחית את זמן ההמתנה הנתפס ומשפר את חוויית המשתמש.
איך להאיץ פיתוח עם יצירת קוד?
יצירת קוד של טיפוסים מסכמת GraphQL חוסכת עד 30% מהזמן בכתיבת ממשקי TypeScript. הגדר npx graphql-codegen:
npm install -D @graphql-codegen/cli @graphql-codegen/client-preset npx graphql-codegen init ב-typePolicies ציין סכמה ומסמכים, והפעל strictScalars:
import type { CodegenConfig } from '@graphql-codegen/cli'
const config: CodegenConfig = {
overwrite: true,
schema: 'http://localhost:4000/graphql',
documents: 'src/**/*.graphql',
generates: {
'src/gql/': {
preset: 'client',
config: {
useTypeImports: true,
strictScalars: true,
scalars: {
DateTime: 'string',
UUID: 'string'
}
}
}
}
}
export default config
הרץ keyArgs בפיתוח ו-errorPolicy: 'all' ב-CI.
טעויות נפוצות בהגדרת Apollo Client
הנפוצה ביותר היא הגדרה שגויה של connectionParams. אם לא תגדיר query GetProducts($categoryId: ID!, $offset: Int, $limit: Int) { products(categoryId: $categoryId, offset: $offset, limit: $limit) { items { id name price stock } total hasMore } } עבור שדות פגינציה, המטמון יערבב נתונים מעמודים שונים. הטעות השנייה היא התעלמות מ-import { useQuery } from '@apollo/client' import { GetProductsDocument } from '@/gql/graphql' export function useProducts(categoryId: string) { return useQuery(GetProductsDocument, { variables: { categoryId }, notifyOnNetworkStatusChange: true }) } בטיפול בשגיאות חלקיות. השלישית היא שכחת העברת connectionParams לאימות WebSocket, מה שגורם למינויים להיכשל עם 401.
איך לנפות בעיות מטמון ב-Apollo Client?
השתמש ב-Apollo DevTools: תוסף Chrome/Firefox שמציג את המטמון, היסטוריית השאילתות והמוטציות. הוא מאפשר להריץ שאילתות GraphQL שרירותיות ישירות מהדפדפן. DevTools מקצר את זמן הניפוי ב-40%.
עבודה עם שאילתות, מוטציות ומינויים
לאחר יצירת הקוד, השתמש בטיפוסים ובהוקים שנוצרו. דוגמאות למסמכים והוקים:
query GetProducts($categoryId: ID!, $offset: Int, $limit: Int) {
products(categoryId: $categoryId, offset: $offset, limit: $limit) {
items {
id
name
price
stock
}
total
hasMore
}
} import { useQuery } from '@apollo/client'
import { GetProductsDocument } from '@/gql/graphql'
export function useProducts(categoryId: string) {
return useQuery(GetProductsDocument, {
variables: { categoryId },
notifyOnNetworkStatusChange: true,
})
} מה כלול בעבודה?
- ניתוח סכמת GraphQL קיימת ומסמכים
- הגדרת לקוח עם קישורי HTTP/WS, אימות, טיפול בשגיאות
- הגדרת InMemoryCache עם typePolicies עבור הישויות שלך
- יצירת קוד של טיפוסי TypeScript והוקים (אינטגרציית CI)
- אינטגרציית מינויים ואימות
- בדיקות וניפוי עם Apollo DevTools
- תיעוד שימוש ותחזוקה
תהליך ולוח זמנים
| שלב | משך |
|---|---|
| ניתוח סכמה ומסמכים | 0.5 יום |
| הגדרת לקוח ומטמון | יום אחד |
| יצירת קוד והוקים | יום אחד |
| אינטגרציית מינויים ואימות | 0.5 יום |
| בדיקות וניפוי | יום אחד |
| תיעוד | 0.5 יום |
העלות מחושבת באופן אישי לפי מורכבות הסכמה והיקף העבודה. לוח זמנים משוער: בין 3 ל-5 ימים.
אנחנו מבטיחים: תאימות לכל מחסנית React, תמיכה בגרסאות העדכניות ביותר של @apollo/client, תיעוד מפורט. הניסיון שלנו: יותר מ-15 פרויקטים על Apollo Client, כולל מסחר אלקטרוני בעומס גבוה. קבל ייעוץ—נעריך את הפרויקט שלך תוך יום אחד. הזמן הגדרת Apollo Client לפרויקט שלך—ניצור איתך קשר תוך שעה.







