Czy wiesz jak dodać GraphQL do aplikacji React?

fsgeek.pl 3 lat temu

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ę, iż możemy przekazać tylko jedną instancję klienta. Powoduje to, iż 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żeli zapytanie jest w trakcie
  • error - jeżeli w trakcie zapytania wystąpił błąd, to tutaj będą informacje o nim
  • data - dane zwrócone z backendu

Inne interesujące 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żeli chcesz pobrać dane w wyniku jakiejś akcji to musisz wykorzystać LazyQuery

LazyQuery

To jest rozszerzenie poprzedniego hooka. Różni się tylko tym, iż 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żeli 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, }, ], }); }
Idź do oryginalnego materiału