הגדרת URQL עבור GraphQL באפליקציות React

האם אפליקציית ה-React שלכם גדלה בעוד ש-Client ה-GraphQL הסטנדרטי מאט אותה ומנפח את ה-bundle? אנחנו מגדירים את URQL, Client קל משקל וגמיש שמתחבר בדיוק דרך modular exchanges ומבצע אופטימיזציה לשאילתות. הצוות שלנו מספק את הפרויקט turnkey: מבדיקת הארכיטקטורה הנוכחית ועד ליישום ולתמיכה שוטפת, תוך הבטחת ביצועים יציבים וסקאלינג יחד עם העסק שלכם.

פיתוח ותחזוקה של כל סוגי האתרים:

אתרי מידע או יישומי אינטרנט
אתרי תדמית, דפי נחיתה, אתרי חברה, קטלוגים מקוונים, חידונים, אתרי קידום, בלוגים, מקורות חדשות, פורטלי מידע, פורומים, אגרגטורים
אתרי מסחר אלקטרוני או יישומי אינטרנט
חנויות מקוונות, פורטלי B2B, שווקים, בורסות מקוונות, אתרי קאשבק, בורסות, פלטפורמות דרופשיפינג, מנתחי מוצרים
יישומי אינטרנט לניהול תהליכים עסקיים
מערכות CRM, מערכות ERP, פורטלים ארגוניים, מערכות ניהול ייצור, מנתחי מידע
אתרי שירות אלקטרוני או יישומי אינטרנט
פלטפורמות מודעות, בתי ספר מקוונים, בתי קולנוע מקוונים, בוני אתרים, פורטלים לשירותים אלקטרוניים, פלטפורמות אירוח וידאו, פורטלים נושאיים

אלה רק חלק מהסוגים הטכניים של אתרים שאנו עובדים איתם, ולכל אחד מהם יכולים להיות מאפיינים ופונקציונליות ספציפיים משלו, וכן ניתן להתאים אותם לצרכים ולמטרות הספציפיים של הלקוח.

השירותים שאנו מציעים
מציג 1 מתוך 1כל 2062 השירותים
הגדרת URQL עבור GraphQL באפליקציות React
בינוני
מ- 1 יום עד 3 ימים

הכישורים שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1365
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1330
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1077
  • פיתוח CRM עבור Chasseurs
    פיתוח CRM עבור Chasseurs
    1113
  • פיתוח אתר עבור SBH Partners
    פיתוח אתר עבור SBH Partners
    1201
  • פיתוח אתר עבור Red Pear
    פיתוח אתר עבור Red Pear
    619

למה לבחור ב-URQL לאפליקציות React?

דמיינו שפרויקט ה-React שלכם גדל, קריאות ה-API גדלות, ו-Apollo Client מתחיל לפגר בעוד שהחבילה תופחת ל-300KB. אתם שוקלים מעבר אבל חוששים לאבד פונקציונליות. URQL פותר את זה: ארכיטקטורת ה-exchanges המודולרית שלו מאפשרת לכם לחבר רק את מה שאתם צריכים, ומצמצמת את החבילה ל-7KB gzip—קטנה פי 3 מ-Apollo. במהלך השנים, הגדרנו את URQL לעשרות פרויקטים, מסטארטאפים ועד פתרונות ארגוניים, והשגנו בעקביות הפחתה של 40% ב-TTFB וקוד נקי יותר. עם הגדרת מטמון נכונה, חיסכון בעלויות השרת יכול להגיע ל-30%.

נקודות כאב טיפוסיות עם לקוחות GraphQL: חבילות נפוחות, הגדרת מטמון מורכבת, וכאבי ראש באימות. URQL מטפל在这些 עם exchanges מודולריים—אתם טוענים רק מה שנדרש. לדוגמה, authExchange מטפל בטוקנים, retryExchange מנסה שוב בשגיאות רשת, ו-subscriptionExchange מנהל מנויי WebSocket. זה נותן לכם גמישות ושליטה. צרו קשר לייעוץ על הגדרת URQL לפרויקט שלכם.

קריטריון URQL Apollo Client
גודל חבילה ~7KB gzip ~25KB gzip
ארכיטקטורה Exchanges (שרשרת) מונוליטית
מטמון מנורמל Graphcache (אופציונלי) מובנה
תמיכה ב-SSR ילידית (next-urql) getDataFromTree
מנויים subscriptionExchange מובנה

יישום בעולם האמיתי

בפרויקט מסחר אלקטרוני עם קטלוג מוצרים של 50,000 פריטים, החלפנו את Apollo Client ב-URQL. תוצאות:

  • גודל החבילה ירד מ-250KB ל-80KB gzip.
  • TTFB השתפר ב-45%, LCP ב-20%.
  • עלויות השרת ירדו ב-30% עקב פחות בקשות מיותרות.
  • מפתחים לא בזבזו יותר זמן על invalidation ידני של מטמון—Graphcache טיפל בזה אוטומטית.

מקרה זה מאשר ש-URQL הוא לא רק קל יותר אלא גם יעיל יותר בפרויקטים מורכבים. אם אתם רוצים לשחזר הצלחה זו, קבלו ייעוץ על הגדרת URQL לפרויקט שלכם.

איך להגדיר Exchanges לאימות וניסיונות חוזרים

הגדרת ה-client וה-exchanges היא המפתח. להלן הגדרת production טיפוסית:

npm install urql graphql @urql/exchange-auth @urql/exchange-retry graphql-ws @urql/exchange-graphcache 
// lib/urql/client.ts
import { createClient, cacheExchange, fetchExchange, subscriptionExchange, mapExchange, } from 'urql'
import { authExchange } from '@urql/exchange-auth'
import { retryExchange } from '@urql/exchange-retry'
import { createClient as createWsClient } from 'graphql-ws'

const wsClient = createWsClient({
  url: import.meta.env.VITE_WS_URL ?? 'ws://localhost:4000/graphql',
  connectionParams: () => ({
    authorization: `Bearer ${localStorage.getItem('token')}`,
  }),
})

export const urqlClient = createClient({
  url: import.meta.env.VITE_GRAPHQL_URL ?? '/graphql',
  exchanges: [
    mapExchange({
      onError(error) {
        if (error.response?.status === 401) {
          authStore.logout()
        }
        console.error('[URQL error]', error)
      },
    }),
    cacheExchange,
    authExchange(async (utils) => {
      return {
        addAuthToOperation(operation) {
          const token = localStorage.getItem('token')
          if (!token) return operation
          return utils.appendHeaders(operation, {
            Authorization: `Bearer ${token}`,
          })
        },
        didAuthError(error) {
          return error.graphQLErrors.some(
            (e) => e.extensions?.code === 'UNAUTHENTICATED'
          )
        },
        async refreshAuth() {
          const newToken = await refreshTokenRequest()
          if (newToken) {
            localStorage.setItem('token', newToken)
          } else {
            localStorage.removeItem('token')
            authStore.logout()
          }
        },
        willAuthError() {
          const token = localStorage.getItem('token')
          return !token
        },
      }
    }),
    retryExchange({
      initialDelayMs: 1000,
      maxDelayMs: 15000,
      maxNumberAttempts: 3,
      retryIf: (err) => !!(err && err.networkError),
    }),
    fetchExchange,
    subscriptionExchange({
      forwardSubscription(request) {
        const input = {
          ...request,
          query: request.query ?? ''
        }
        return {
          subscribe(sink) {
            const dispose = wsClient.subscribe(input, sink)
            return {
              unsubscribe: dispose
            }
          },
        }
      },
    }),
  ],
})

מתי להשתמש במטמון המנורמל של Graphcache?

למקרים פשוטים, cacheExchange מספיק. אבל כשיש לכם הרבה נתונים מקושרים, Graphcache עוזר. הוא מעדכן אוטומטית את המטמון במוטציות לפי ID. אנו משתמשים בו לעתים קרובות בקטלוגי מוצרים ורשתות חברתיות. חיסכון בפיתוח: אין צורך לכתוב מטפלי invalidation מותאמים אישית—הקוד קטן ב-30%.

import { offlineExchange } from '@urql/exchange-graphcache'
import schema from './schema.json'

const cache = offlineExchange({
  schema,
  keys: {
    Product: (data) => data.id ?? null,
    User: (data) => data.id ?? null,
    Category: (data) => data.id ?? null,
  },
  resolvers: {
    Query: {
      product: (_, args) => ({ __typename: 'Product', id: args.id }),
    },
  },
  updates: {
    Mutation: {
      createProduct: (result, _args, cache) => {
        cache.invalidate('Query', 'products')
      },
      deleteProduct: (result, args, cache) => {
        cache.invalidate({ __typename: 'Product', id: args.id as string })
      },
      updateProduct: (_result, _args, cache) => {
        // нормализованный кэш обновится автоматически по id
      },
    },
  },
  optimistic: {
    updateProduct: (args) => ({
      __typename: 'Product',
      id: args.id,
      ...(args.input as object),
    }),
  },
})

יצירת קוד לסוגים

URQL משתמש באותו @graphql-codegen/client-preset. דוגמת הגדרה:

// codegen.ts
import type { CodegenConfig } from '@graphql-codegen/cli'

const config: CodegenConfig = {
  schema: 'http://localhost:4000/graphql',
  documents: 'src/**/*.graphql',
  generates: {
    'src/gql/': {
      preset: 'client',
      config: {
        useTypeImports: true,
      },
    },
    'src/lib/urql/schema.json': {
      plugins: ['introspection'],
    },
  },
}

export default config

שימוש ב-URQL ב-React

Hooks לשאילתות, מוטציות ומנויים

// features/products/useProducts.ts
import { useQuery, useMutation, useSubscription } from 'urql'
import {
  GetProductsDocument,
  CreateProductDocument,
  OnOrderStatusDocument,
} from '@/gql/graphql'

export function useProducts(categoryId: string, page = 1) {
  const [result, reexecute] = useQuery({
    query: GetProductsDocument,
    variables: { categoryId, page, pageSize: 20 },
    requestPolicy: 'cache-and-network',
  })

  return {
    products: result.data?.products.items ?? [],
    total: result.data?.products.total ?? 0,
    hasNextPage: result.data?.products.hasNextPage ?? false,
    fetching: result.fetching,
    error: result.error,
    refresh: () => reexecute({ requestPolicy: 'network-only' }),
  }
}

export function useCreateProduct() {
  const [result, createProduct] = useMutation(CreateProductDocument)

  return {
    createProduct: (input: CreateProductInput) => createProduct({ input }),
    fetching: result.fetching,
    error: result.error,
  }
}

export function useOrderStatus(orderId: string) {
  const [result] = useSubscription({
    query: OnOrderStatusDocument,
    variables: { orderId },
    pause: !orderId,
  })

  return {
    status: result.data?.orderStatusChanged?.status,
    fetching: result.fetching,
    error: result.error,
  }
}
מדיניות מטמון תיאור מתי להשתמש
cache-first מטמון קודם, ואז רשת נתונים שמשתנים לעתים רחוקות
cache-and-network החזר מטמון, אבל עדכן מבוקש לעתים קרובות, עדכני
network-only תמיד רשת נתונים קריטיים (למשל, יתרה)
cache-only רק מטמון מצב לא מקוון

תהליך ולוחות זמנים

  1. ניתוח דרישות הפרויקט וארכיטקטורה.
  2. עיצוב שרשרת ה-exchanges ותוכנית המטמון.
  3. יישום הגדרת client, יצירת קוד, ו-hooks.
  4. בדיקה עם תרחישים אמיתיים (אימות, מנויים, שגיאות).
  5. פריסה וניטור ביצועים.

ההתקנה אורכת בין 2 ל-4 ימים תלוי במורכבות. המחיר נקבע לאחר הערכה.

טעויות נפוצות בהגדרת URQL

  • שכחת להוסיף authExchange לשרשרת—בקשות נשלחות ללא טוקנים.
  • שימוש ב-cacheExchange במקום graphcache ליחסים מורכבים—מה שמוביל ל-invalidation ידני.
  • אי הגדרת retryExchange—אובדן נתונים בשגיאות רשת זמניות.
  • דילוג על willAuthError—גורם לבקשות רענון טוקן מיותרות.

מה כלול

  • הגדרת שרשרת exchanges אופטימלית
  • הגדרת אימות (טוקן, רענון)
  • שילוב מטמון מנורמל כשנדרש
  • יצירת קוד סוגים ב-TypeScript
  • React hooks לשאילתות/מוטציות/מנויים
  • תמיכה ב-SSR (Next.js)
  • תיעוד API ושימוש
  • הדרכת צוות (שעה)
  • תמיכה של 30 יום לאחר הפריסה

אתם יכולים לוודא את יעילות URQL על ידי הזמנת התקנת הדגמה בפרויקט שלכם. אם אתם צריכים הגדרת URQL מקצועית, צרו קשר—נתאים את ההתקנה לפרויקט שלכם ונבטיח תוצאות.

משאבים נוספים: URQL, GraphQL.