5 روش برای واکشی داده‌ها از یک GraphQL API در React

آفلاین
user-avatar
عرفان حشمتی
30 تیر 1400, خواندن در 10 دقیقه

در این مقاله می‌خواهیم پنج راهی که می‌توان داده‌ها را از یک GraphQL API در کتابخانه React واکشی کرد، معرفی کنیم.

با اینکه چند کتابخانه معروف وجود دارد که برای تعامل با GraphQL API در برنامه React ساخته شده‌اند، اما روش‌های مختلفی هم برای واکشی داده‌ها از GraphQL وجود دارد.

در اینجا نمونه کدهایی را آورده‌ایم که به شما نشان می‌دهد چگونه داده‌ها را در کوتاه ترین زمان ممکن و در کمترین خط کد واکشی کنید و چگونه با هر یک از این روش‌ها اتصال برنامه React را با GraphQL برقرار کنید.

آیا می‌خواهید با ری‌اکت و GraphQL برنامه‌های شگفت انگیز بسازید؟ React Bootcamp را امتحان کنید.

شروع کار

در مثال‌هایی که ذکر خواهیم کرد از SpaceX GraphQL API برای واکشی داده‌ها و نمایش 10 ماموریتی که شرکت SpaceX قبلا انجام داده است، استفاده می‌کنیم.

اگر می‌خواهید برنامه React خود را به یک GraphQL API متصل کنید، از کد زیر استفاده کنید. در این مثال‌ها می‌خواهیم از پیشرفته‌ترین کتابخانه کلاینت GraphQL برای React به ساده‌ترین شکل ممکن کوئری بنویسیم.

1. Apollo Client

محبوب‌ترین و جامع‌ترین کتابخانه GraphQL آپولو کلاینت است.

نه تنها می‌توانید از آن برای واکشی داده‌های از راه دور با GraphQL استفاده کنید (کاری که ما در اینجا انجام می‌دهیم)، بلکه به ما امکان می‌دهد داده‌ها را به صورت محلی نیز مدیریت کنیم (هم از طریق حافظه کش داخلی و هم از طریق API مدیریت state).

برای شروع کار با این کتابخانه، باید وابستگی اصلی Apollo Client و همچنین GraphQL را نصب کنیم:

npm install @apollo/client graphql

رویکرد آپولو کلاینت به این صورت است که در کل برنامه ما استفاده خواهد شد. برای این کار از یک کامپوننت ویژه برای انتقال کلاینت آپولو ایجاد شده در کل درخت کامپوننت استفاده می‌کنیم.

هنگامی که Apollo Client خود را ایجاد می‌کنیم باید مقدار uri یعنی نقطه پایانی GraphQL را مشخص کنیم. علاوه بر این باید یک حافظه کش را در نظر بگیریم. Apollo Client حافظه کش خود را دارد که برای ذخیره سازی یا ذخیره محلی و مدیریت نمایش داده‌ها و اطلاعات مربوط به آنها استفاده می‌شود:

import React from "react";
import ReactDOM from "react-dom";
import { ApolloProvider, ApolloClient, InMemoryCache } from "@apollo/client";

import App from "./App";

const client = new ApolloClient({
  uri: "https://api.spacex.land/graphql/",
  cache: new InMemoryCache()
});

const rootElement = document.getElementById("root");
ReactDOM.render(
  <ApolloProvider client={client}>
    <App />
  </ApolloProvider>,
  rootElement
);

بعد از اینکه provider و client را در کامپوننت برنامه خود تنظیم کردیم، می‌توانیم از همه هوک‌های مختلفی که Apollo Client به ما می‌دهد برای عملیات GraphQL که شامل query، mutation و subscription است، استفاده کنیم. حتی می‌توانیم از Apollo Client ایجاد شده مستقیما با استفاده از هوک سفارشی به نام useApolloClient استفاده کنیم.

از آنجا که ما در اینجا فقط در حال کوئری نوشتن برای داده‌ها هستیم، از هوک useQuery استفاده خواهیم کرد.

سپس یک کوئری GraphQL را به عنوان اولین آرگومان برای نوشتن کوئری مورد نظر خود قرار خواهیم داد. ما از تابع gql استفاده می‌کنیم که کارهای مختلفی را انجام می‌دهد مانند برجسته سازی سینتکس و قالب بندی خودکار در صورت استفاده از ابزار Prettier برای پروژه.

پس از اجرای این کوئری، مقادیر data، loading و error را دریافت می کنیم:

import React from "react";
import { useQuery, gql } from "@apollo/client";

const FILMS_QUERY = gql`
  {
    launchesPast(limit: 10) {
      id
      mission_name
    }
  }
`;

export default function App() {
  const { data, loading, error } = useQuery(FILMS_QUERY);

  if (loading) return "Loading...";
  if (error) return <pre>{error.message}</pre>

  return (
    <div>
      <h1>SpaceX Launches</h1>
      <ul>
        {data.launchesPast.map((launch) => (
          <li key={launch.id}>{launch.mission_name}</li>
        ))}
      </ul>
    </div>
  );
}

قبل از نمایش داده‌ها می‌خواهیم loading را کنترل کنیم. هنگامی که در حالت بارگیری هستیم، از یک نقطه انتهایی کوئری را واکشی می‌کنیم.

همچنین می‌خواهیم وضعیت رخ دادن خطا را مدیریت کنیم. برای این کار می‌توانیم با ایجاد یک خطای سینتکسی در درخواست خود مانند پرس و جو برای فیلدی که وجود ندارد، یک خطا را شبیه سازی کنیم. همچنین برای مقابله با این خطا می‌توانیم به راحتی پیامی را از error.message برگردانیم و نمایش دهیم.

2. Urql

یکی دیگر از کتابخانه‌های ویژه که برنامه‌های React را به GraphQL API متصل می‌کند urql است.

این کتابخانه تلاش می‌کند بسیاری از ویژگی‌ها و سینتکس آپولو را به ما ارائه دهد، با اینکه حجم کمی داشته و به کد راه اندازی کمتری هم نیاز دارد. اگر بخواهیم قابلیت‌های caching را به ما می‌دهد، اما شامل کتابخانه مدیریت state یکپارچه مانند Apollo نمی‌شود.

برای استفاده از urql به عنوان کتابخانه کلاینت GraphQL خود باید پکیج‌های urql و GraphQL را نصب کنید.

npm install urql graphql

دقیقا مانند Apollo می‌خواهیم از کامپوننت اختصاصی Provider استفاده کنیم و با نقطه پایانی GraphQL خود یک کلاینت ایجاد کنیم. توجه داشته باشید که نیازی به مشخص کردن کش نداریم.

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { createClient, Provider } from 'urql';

const client = createClient({
  url: 'https://api.spacex.land/graphql/',
});

const rootElement = document.getElementById("root");
ReactDOM.render(
  <Provider value={client}>
    <App />
  </Provider>,
  rootElement
);

urql شبیه به آپولو بسیاری از هوک‌های سفارشی را به ما ارائه می‌دهد که همه عملیات استاندارد GraphQL را کنترل می‌کنند، بنابراین نام‌های مشابهی هم دارند.

مجددا می‌توانیم از هوک useQuery موجود در پکیج urql استفاده کنیم. همچنین به جای اینکه به تابع gql احتیاج داشته باشیم، می‌توانیم آن را دراپ کنیم و فقط از یک الگوی واقعی برای نوشتن کوئری استفاده می‌کنیم.

هنگام فراخوانی useQuery یک آرایه به دست می‌آوریم که می‌توانیم آن را به عنوان یک آرایه به جای یک شی از بین ببریم. اولین عنصر در این آرایه یک شی است به نام result که به ما تعدادی از خصوصیاتی را می‌دهد که می‌توانیم ساختار آنها را از بین ببریم مثل: data، fetching و error.

import React from "react";
import { useQuery } from 'urql';

const FILMS_QUERY = `
  {
    launchesPast(limit: 10) {
      id
      mission_name
    }
  }
`;

export default function App() {
  const [result] = useQuery({
    query: FILMS_QUERY,
  });

  const { data, fetching, error } = result;

  if (fetching) return "Loading...";
  if (error) return <pre>{error.message}</pre>

  return (
    <div>
      <h1>SpaceX Launches</h1>
      <ul>
        {data.launchesPast.map((launch) => (
          <li key={launch.id}>{launch.mission_name}</li>
        ))}
      </ul>
    </div>
  );
}

به روشی مشابه نمایش داده‌هایی که با آپولو واکشی می‌کردیم، می‌توانیم همزمان با واکشی داده‌های ریموت، هم از error و هم از loading خود استفاده کنیم.

3. React Query + GraphQL Request

توجه به این نکته مهم است که برای تعامل با GraphQL API نیازی به یک کتابخانه کلاینت پیچیده و سنگین GraphQL مانند urql یا Apollo ندارید، همانطور که بعدا خواهیم دید.

کتابخانه‌هایی مانند Apollo و urql نه تنها برای کمک به ما در انجام تمام عملیات استاندارد GraphQL بلکه برای مدیریت بهتر state سرور در کلاینت React از طریق تعدادی ابزار اضافی ایجاد شده‌اند. همراه با این واقعیت که آنها با هوک‌های سفارشی همراه هستند که مدیریت کارهای تکراری مانند loading، error و سایر موارد مرتبط را ساده می‌کنند.

با توجه به این نکته بیایید نگاهی بیندازیم به اینکه چگونه می‌توانیم از یک کتابخانه GraphQL برای واکشی داده‌های خود استفاده کنیم و این را با یک روش بهتر برای مدیریت و پنهان کردن state سرور که در برنامه خود قرار داده‌ایم، ترکیب کنیم. راهی که میتوانیم دادهها را خیلی ساده واکشی کنیم بهره گیری از پکیج graphql-request می‌باشد.

GraphQL Request کتابخانه‌ای است که نیازی به راه اندازی client یا provider ندارد. این اساسا تابعی است که فقط یک نقطه پایانی و یک کوئری را می‌پذیرد. بسیار شبیه به یک کلاینت HTTP فقط باید این دو مقدار را ارسال کرده و داده‌های خود را دریافت کنیم.

حال اگر بخواهیم state را در سراسر برنامه خود مدیریت کنیم، می‌توانیم از یک کتابخانه عالی استفاده کنیم که معمولا برای تعامل با Rest API استفاده می‌شود، اما به همان اندازه برای GraphQL API نیز مفید است و نام آن React Query می‌باشد. این کتابخانه به ما هوک‌های useQuery و useMutation را ارائه می‌دهد که وظایفی مشابه عملکرد هوک‌های Apollo و urql را انجام می‌دهند.

React Query همچنین به همراه یک کامپوننت یکپارچه Dev Tools به ما گروهی از ابزارها را برای مدیریت state می‌دهد که به ما کمک می‌کند ببینیم چه مواردی در حافظه کش React Query ذخیره شده است.

با جفت کردن کلاینت اصلی GraphQL و درخواست GraphQL با React Query تمام قابلیت یک کتابخانه کامل مانند urql یا Apollo را به دست می‌آوریم.

برای شروع کار فقط باید React Query و GraphQL Request را نصب کنیم:

npm install react-query graphql-request

سپس از کامپوننت Provider در React Query استفاده کرده و یک کلاینت کوئری ایجاد می‌کنیم که در صورت تمایل می‌توانیم برخی از تنظیمات واکشی پیش فرض داده را انجام دهیم و بعد در خود کامپوننت برنامه یا سایر کامپوننت‌های آن می‌توانیم از هوک useQuery استفاده کنیم.

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { QueryClient, QueryClientProvider } from "react-query";

const client = new QueryClient();

const rootElement = document.getElementById("root");
ReactDOM.render(
  <QueryClientProvider client={client}>
    <App />
  </QueryClientProvider>,
  rootElement
);

برای ذخیره نتیجه کار خود در حافظه کش React Query فقط باید یک مقدار کلیدی به عنوان اولین آرگومان به آن اختصاص دهیم. این کار به ما اجازه می‌دهد تا به راحتی داده‌ها را از حافظه پنهان بیرون کشیده و برای بازیابی داده‌های به روز شده، کوئری داده شده را دوباره بازیابی یا باطل می‌کنیم.

از آنجا که در حال واکشی داده‌های در حال اجرا هستیم، این کوئری را "launch" می‌نامیم.

یک بار دیگر این هوک نتیجه درخواست شما را برمی‌گرداند. برای استفاده از آرگومان دوم باید نحوه واکشی داده‌ها را مشخص کنیم و در نهایت React Query از promiseی که درخواست GraphQL برمی‌گرداند مراقبت خواهد کرد.

import React from "react";
import { request, gql } from "graphql-request";
import { useQuery } from "react-query";

const endpoint = "https://api.spacex.land/graphql/";
const FILMS_QUERY = gql`
  {
    launchesPast(limit: 10) {
      id
      mission_name
    }
  }
`;

export default function App() {
  const { data, isLoading, error } = useQuery("launches", () => {
    return request(endpoint, FILMS_QUERY);
  });

  if (isLoading) return "Loading...";
  if (error) return <pre>{error.message}</pre>;

  return (
    <div>
      <h1>SpaceX Launches</h1>
      <ul>
        {data.launchesPast.map((launch) => (
          <li key={launch.id}>{launch.mission_name}</li>
        ))}
      </ul>
    </div>
  );
}

مشابه Apollo شیئی را دریافت می‌کنیم که می‌توانیم مقادیر داده‌های آن را از بین ببریم، چه در loading باشیم و چه در error.

4. React Query + Axios

می‌توانیم از کتابخانه‌های کلاینت ساده HTTP که هیچ ارتباطی با GraphQL ندارند، برای واکشی داده‌های خود استفاده کنیم.

در این حالت می‌توانیم از کتابخانه معروف axios استفاده کنیم. یک بار دیگر آن را با React Query جفت می‌کنیم تا تمام هوک‌های ویژه و مدیریت state را به دست آوریم.

npm install react-query axios

استفاده از یک کلاینت HTTP مانند Axios برای اجرای کوئری از GraphQL API نیاز به انجام درخواست POST به نقطه پایانی API دارد. برای داده‌هایی که در درخواست خود ارسال می‌کنیم، یک شی را با خصوصیتی به نام query در نظر می‌گیریم که در کوئری films تنظیم خواهد شد.

با axios باید اطلاعات بیشتری در مورد چگونگی حل این promise و بازگرداندن اطلاعات خود اضافه کنیم. همچنین باید به React Query بگوییم که داده در کجا قرار دارد تا بتوان آن را در خصوصیت data که useQuery برمی‌گرداند قرار داد.

به طور خاص، داده‌ها را در خصوصیت data در response.data برمی‌گردانیم:

 

import React from "react";
import axios from "axios";
import { useQuery } from "react-query";

const endpoint = "https://api.spacex.land/graphql/";
const FILMS_QUERY = `
  {
    launchesPast(limit: 10) {
      id
      mission_name
    }
  }
`;

export default function App() {
  const { data, isLoading, error } = useQuery("launches", () => {
    return axios({
      url: endpoint,
      method: "POST",
      data: {
        query: FILMS_QUERY
      }
    }).then(response => response.data.data);
  });

  if (isLoading) return "Loading...";
  if (error) return <pre>{error.message}</pre>;

  return (
    <div>
      <h1>SpaceX Launches</h1>
      <ul>
        {data.launchesPast.map((launch) => (
          <li key={launch.id}>{launch.mission_name}</li>
        ))}
      </ul>
    </div>
  );
}

5. React Query + Fetch API

ساده‌ترین راه برای دستیابی به داده‌های مختلف این است که فقط از React query به علاوه Fetch API استفاده کنید.

از آنجا که Fetch API در همه مرورگرهای مدرن گنجانده شده است، نیازی به نصب کتابخانه شخص ثالث آن نداریم و فقط باید React Query را در برنامه خود نصب کنیم.

npm install react-query

هنگامی که کلاینت React Query را در اختیار کل برنامه قرار داد، می‌توانیم کد axios خود را fetch عوض کنیم.

چیزی که کمی متفاوت به نظر می‌رسد این است که ما باید یک هدر مشخص کنیم که شامل نوع محتوای داده‌ای باشد که می‌خواهیم از درخواست خود برگردانیم. در این حالت داده از نوع JSON است.

همچنین باید شی مورد نظر خود را که به عنوان payload ارسال می‌کنیم با خصوصیت کوئری تنظیم شده بر روی films رشته بندی کنیم:

import React from "react";
import axios from "axios";
import { useQuery } from "react-query";

const endpoint = "https://api.spacex.land/graphql/";
const FILMS_QUERY = `
  {
    launchesPast(limit: 10) {
      id
      mission_name
    }
  }
`;

export default function App() {
  const { data, isLoading, error } = useQuery("launches", () => {
    return fetch(endpoint, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ query: FILMS_QUERY })
    })
      .then((response) => {
        if (response.status >= 400) {
          throw new Error("Error fetching data");
        } else {
          return response.json();
        }
      })
      .then((data) => data.data);
  });

  if (isLoading) return "Loading...";
  if (error) return <pre>{error.message}</pre>;

  return (
    <div>
      <h1>SpaceX Launches</h1>
      <ul>
        {data.launchesPast.map((launch) => (
          <li key={launch.id}>{launch.mission_name}</li>
        ))}
      </ul>
    </div>
  );
}

یک مزیت استفاده ازaxios  به همراه fetch این است که به طور خودکار خطاها را برای ما کنترل می‌کند. با fetch همانطور که در کد زیر مشاهده میکنید، باید یک کد وضعیت خاص به ویژه یک کد وضعیت بالای 400 را بررسی کنیم.

این بدان معنی است که درخواست ما دوباره منجر به خطا می‌شود. در این صورت باید به صورت دستی خطا را برطرف کنیم که با هوک useQuery انجام خواهد شد. در غیر این صورت اگر پاسخ 200 یا 300 باشد، به این معنی است که درخواست موفقیت آمیز بوده و ما به سادگی داده‌های JSON را برمی‌گردانیم و نمایش می‌دهیم.

سخن پایانی

این مقاله قصد داشت چندین روش مختلف برای واکشی موثر داده‌ها از یک GraphQL API در React را به شما نشان دهد.

امیدوارم بتوانید مناسب‌ترین گزینه را ارزیابی و انتخاب کرده و به نحو احسن از آن در پروژه‌های آیندتان استفاده کنید.

منبع

چه امتیازی به این مقاله می دید؟
خیلی بد
بد
متوسط
خوب
عالی

دیدگاه‌ها و پرسش‌ها

برای ارسال دیدگاه لازم است، ابتدا وارد سایت شوید.

در حال دریافت نظرات از سرور، لطفا منتظر بمانید

در حال دریافت نظرات از سرور، لطفا منتظر بمانید

آفلاین
user-avatar
عرفان حشمتی @heshmati74
مهندس معماری سیستم های کامپیوتری، طراح و توسعه دهنده وب سایت
دنبال کردن

گفتگو‌ برنامه نویسان

بخشی برای حل مشکلات برنامه‌نویسی و مباحث پیرامون آن وارد شو