Czy wiesz jak dodać GraphQL do aplikacji React?

Aleksander Patschek

Czas czytania: 3 min
Liczba słów: 521
Data: 15-06-2021
Udostępnij:

Graphql jest coraz popularniejszy w aplikacjach. Pozwala na pobieranie dokładnie tych danych, jakich potrzebujemy. W jednym z poprzednich postów pokazałem jak to zaimplementować na backendzie. Dziś przyszedł czas na frontend.

Instalacja i konfiguracja

Najpierw rzeczy oczywiste - instalacja i konfiguracja potrzebnych bibliotek. Będę oczywiście konfigurował projekt napisany w React.

npm i @apollo/client graphql

Do poprawnego działania potrzebujemy tzw.: klienta. Jest to w minimalnej konfiguracji adres serwera graphql, z którego będziemy pobierać dane i rodzaj cache'a. Będziemy z niego korzystać przy każdej operacji.

import { ApolloClient, InMemoryCache } from '@apollo/client';

const client = new ApolloClient({
  uri: 'http://localhost:3000/graphql',
  cache: new InMemoryCache()
});

Uwaga! URL do Graphql najlepiej przekazywać w zmiennej środowiskowej

Najlepiej jest wyciągnąć konfigurację klienta do osobnego pliku. Dlaczego? Ponieważ będziemy mogli go importować w wielu miejscach. Możemy również mieć kilka klientów w jednej aplikacji.

Dodatkowo w React możemy skorzystać z Contextu, by dostarczyć domyślnego klienta i uprościć pracę.

<ApolloProvider client={client}>
  <App />
</ApolloProvider>

Nic nie stoi na przeszkodzie, by osobne części systemu korzystały z różnych Provider'ów. Warto zwrócić uwagę, że możemy przekazać tylko jedną instancję klienta. Powoduje to, że w sytuacji, gdy korzystamy z kilku klientów, może to być nieintuicyjne.

Rodzaje operacji

W GraphQL mamy kilka rodzajów operacji, które możemy wykonać:

  • Query - do pobierania danych
  • Mutation - do aktualizacji danych
  • Subscription - do nasłuchiwania na dane

Do każdej z tych operacji mamy odpowiednie funkcje, które możemy wykorzystać. Dziś skupię się na Query i Mutation

Query

Najprostszą operacją jest pobieranie danych. W GraphQL polega to na wysłaniu odpowiedniego Query. W Apollo Graphql mamy dostępne dwa hooki: useQUery i useLazyQuery. Zacznę od tego pierwszego.

const query = gql`
	{
	  links {
	    url,
	    name
	  }
	}
`

const {loading, error, data} = useQuery(query, {
	fetchPolicy: "network-only",
})

Do wykonania dowolnej operacji potrzebujemy query z Graphql'a. Tworzymy je przy pomocy funkcji gql. Sam hook wymaga od nas podania tylko tego query do poprawnego działania. Ale oprócz tego możemy przekazać obiekt z dodatkowymi ustawieniami. To z czego ja najcześciej korzystam to:

  • variables - do przekazywania zmiennych np.: filtry
  • fetchPolicy - do ustawienia sposobu, w jaki chce pobrać dane - czy zawsze to ma być zapytanie na backend, czy chcemy wykorzystać cache.

To, co dostajemy to obiekt z odpowiednimi polami. Do tych najczęściej wykorzystywanych można zaliczyć:

  • loading - true jeśli zapytanie jest w trakcie
  • error - jeśli w trakcie zapytania wystąpił błąd, to tutaj będą informacje o nim
  • data - dane zwrócone z backendu

Inne ciekawe pola to:

  • refetch - do ponownego uruchomienia query z tymi samymi zmiennymi.
  • fetchMore - wykorzystywane do paginacji, by pobrać kolejną porcję danych

Ten hook zawsze wykonuje się po zamontowaniu komponentu na stronie. Jeśli chcesz pobrać dane w wyniku jakiejś akcji to musisz wykorzystać LazyQuery

LazyQuery

To jest rozszerzenie poprzedniego hooka. Różni się tylko tym, że zwraca tablicę zamiast obiektu i nie wykonuje się automatycznie. Za to pierwszy element tablicy jest funkcją, która pozwala na pobranie danych. Wygląda to następująco:

const [fetchLinks, {loading, error, data}] = useLazyQuery(query, {
	fetchPolicy: "network-only",
})

const fetchLinks = ()=>{
	fetchLinks();
}

Reszta elementów jest bez zmian.

Mutation

Na sam koniec zostawiłem mutacje. Jeśli chodzi o strukturę, to wygląda podobnie do LazyQuery. Czyli jako rezultat hooka dostajemy tablicę, gdzie pierwszym elementem jest funkcja, która umożliwia wykonanie mutacji.

const mutation = gql`
mutation AddLink($url: String, $name: String) {
    addLink(url: $url, name: $name){
      name,
      url
    }
  }  
`

const [addLinkMutation, {called, loading, data, error}] = useMutation(mutation);

Tak samo wygląda obiekt z rezultatem wykonania mutacji. Dodatkowym elementem jest flaga called. A jak przekazać zmienne do mutacji? Bardzo prosto - podczas jej wywoływania.

const addLink = ()=>{
  addLinkMutation({variables: {"url":"test", "name":"foo"}});
}

Możemy też tego użyć w inny sposób. Zamiast pobierać dane bezpośrednio z hooka, możemy je pobierać z funkcji mutującej.

const addLink = async ()=>{
    const {data} = await addLinkMutation({variables: {"url":"test", "name":"foo"}});

    console.log(data);
} 

Ciekawym parametrem jaki możemy przekazać w mutacji, obok variables, jest refetchQueries. Pozwala na wykonanie query, po tym jak się wykona mutacja. Możesz tego użyć np.: do odświeżenia widoku po tym, jak użytkownik zaktualizował dane. Przykładowy kod wygląda następująco:

const { loading, data } = useQuery(query, {
    fetchPolicy: "network-only",
})

const [addLinkMutation] = useMutation(mutation);

const addLink = async () => {
  await addLinkMutation({
      variables: { "url": "test", "name": "foo" },
      refetchQueries: [
          {
              query: query,
          },
      ],
  });
}
Jeśli podobał ci się ten artykuł to dołącz do newslettera. Dostaniesz dodatkowe treści do każdego postu oraz eksluzywne materiały, które pomogą ci pisac lepszy kod Chcę uzyskać dostęp do bonusów