Codați o aplicație cu GraphQL, reacționați Native și AWS AppSync aplicația

Ce veți crea

În aceste tutoriale, vă arăt cum să creați și să interacționați cu o bază de date GraphQL utilizând AWS AppSync și React Native. Această aplicație va avea funcționalități în timp real și offline, ceva ce ieșim din cutie cu AppSync. 

În postul anterior, am creat back-end-ul GraphQL cu serviciul Amazon AppSync. Verificați dacă nu ați făcut-o deja. Sau, dacă doriți o introducere în GraphQL, aruncați o privire la unele dintre celelalte postări ale noastre.

În acest post, vom încheia totul prin trecerea prin construirea clientului React Native. Proiectul este un pic prea complicat pentru a vă trece prin pas cu pas, dar vă voi explica arhitectura proiectului și vă voi arăta părțile cheie ale codului sursă.

Prezentare generală a arhitecturii și a structurii folderului

Aplicația noastră va avea un punct de intrare principal care va consta din două vizualizări cu file. O filă va lista orașele din baza noastră de date GraphQL, iar cealaltă va fi formularul de intrare pentru a adăuga un oraș nou. Orase fila va fi un navigator care va permite utilizatorului să navigheze către orașele individuale.

Vom păstra componentele principale în sursă folder, și va avea alte foldere în src director pentru a organiza mutațiile, interogările și abonamentele noastre GraphQL.

Vom avea, de asemenea, un bunuri dosar pentru a ține imaginile noastre.

Crearea și configurarea clientului React Nativ

Pentru referință, aruncăm o privire la codul final al acestei aplicații în replica GitHub tutorial, dar voi schița câțiva pași pe care i-am făcut pentru a crea aplicația de la zero.

În primul rând, am creat o nouă aplicație Nativă React folosind Expo. 

Odată ajuns în proiectul nou creat, am instalat dependențele noastre. Pentru funcționalitățile GraphQL și AppSync am folosit următoarele dependențe:

aws-appsync aws-appsync-reacție grafică-tag reaction-apollo uuid

De asemenea, am folosit următoarele dependențe pentru designul UI:

reacționează-reacționează-reacționează-elemente native reacționează-vectori-nativi-icoane

De asemenea, odată ce biblioteca Vector Icons a fost instalată, am legat-o:

reactiv-nativă reacție-icoane vector-nativ

După instalarea dependențelor, am descărcat AppSync.js fișier din consola noastră AppSync. În consola noastră de proiect AppSync, am ales Răspunde Nativ în partea de jos și faceți clic pe portocaliu Descarca pentru a descărca acest fișier de configurare.


Acest fișier de configurare conține informațiile despre clientul AppSync necesare pentru a crea un client nou. 

Configurarea furnizorului și stocarea

Nivelul superior al aplicației este locul în care vom face configurația noastră pentru a conecta API-ul AppSync cu clientul React Native.Dacă ați folosit anterior Redux sau React Apollo, toate acestea vor fi cunoscute. Dacă nu, amintiți-vă că orice copil al unui copil Furnizor de, în cazul nostru ApolloProvider, va avea acces la funcționalitatea dată. 

Următorul cod este noul nostru App.js fișier, care este componenta principală importată de la noi index.js punct de intrare.

import Reacționați din importul "react" import Tab-uri din importul "./src/Tabs" AWSAppSyncClient din "aws-appsync"; import Rehydrated din "aws-appsync-react"; import ApolloProvider de la "react-apollo"; importați appSyncConfig din "./aws-exports"; const client = nou AWSAppSyncClient (url: appSyncConfig.graphqlEndpoint, regiune: appSyncConfig.region, auth: type: appSyncConfig.authType, apiKey: appSyncConfig.apiKey,); const cuProvider = () => (      ); export implicit cu

În acest fișier, configurăm un nou client AppSync utilizând o combinație de AWSAppSyncClient constructor de la AWS-appsync precum și configurația din cadrul nostru AWS-exports.js fișier, care oferă URL-ul API-ului GraphQL, regiunea, tipul de autentificare și cheia API pentru autentificare.

Apoi, împachetăm punctul nostru de intrare principal, Tabs.js fișierul care va conține navigația în tab, într - un fișier ApolloProvider și treci în clientul AppSync ca propunerea clientului. De asemenea, înfășurăm Tab-uri componentă într-un rehidratate din care importăm AWS-appsync reacționează. Astfel, vom fi siguri că am citit din spațiul de stocare asincron și ne-am rehidratat memoria cache înainte de redarea interfeței.

Acum, aplicația noastră va putea să interogheze date din punctul nostru de vedere AppSync și să efectueze mutații și abonamente!

Navigare

Punctul principal de intrare al aplicației este o navigare cu file, implementată în fișierul Tabs.js cu React Navigation.

Ce am făcut aici este crearea și exportul a TabNavigator cu două file. Acestea sunt:

  1. Orase: Această componentă enumeră orașele noastre și este o componentă de navigare în sine. Această componentă este un navigator pentru că vrem să navigăm în fiecare oraș și să vedem locațiile din oraș.
  2. AddCity: Această componentă este o formă pentru a putea adăuga orașe noi.

Componente reutilizabile

Această aplicație are o singură componentă reutilizabilă, personalizată TextInput. Deoarece vom replica acest stil și funcționalitate de mai multe ori, am decis să-l transformăm într-o componentă proprie. Componenta de intrare este implementată în Input.js.

Lista orașelor și navigarea în oraș

Vederea principală a aplicației este o listă de orașe pe care le vom extrage din GraphQL. Vrem să putem naviga de la fiecare oraș listat la o vedere detaliată a orașului în care putem adăuga locații.

Pentru a face acest lucru, facem Cities.js propriul StackNavigator și City.js componenta la care navigăm la alegerea unui oraș. Atunci când faceți clic pe un oraș din Orase, noi îi transmitem numele și id-ul ca elemente de recuzită Oraș.

Cities.js

În această componentă, preluăm folosind listCities interogare, și suntem, de asemenea, abonați la NewCitySubscription, astfel încât atunci când se adaugă un oraș nou, chiar și de la un alt client, vom gestiona acest abonament și vom actualiza gama noastră de orașe. listCities interogare face o serie de orașe disponibile în componenta noastră ca this.props.cities.

City.js

În această componentă, trecem un oraș ca elemente de recuzită din navigație (disponibile ca props.navigation.state.params.city). Folosim orașul id valoare pentru a prelua lista locațiilor pentru orașul ales cu ajutorul listLocations interogare. Ne abonați la noi locații în mod similar cu modul în care ne-am abonat la noi orașe Cities.js, folosind NewLocationSubscription abonament. De asemenea, oferim optimisticResponse și Actualizați funcții pentru adăugarea unui nou oraș. 

Adăugarea orașelor

În cele din urmă, trebuie să implementăm funcționalitatea pentru adăugarea de noi orașe în API-ul GraphQL în fișierul AddCity.js. Pentru a face acest lucru, am conectat o mutație împreună cu o formă care va apela createCity, trecând valoarea intrării din formular.

AddCity are un onAdd funcția pe care o definim în compoziția noastră GraphQL, care nu numai că scrie un nou oraș în baza noastră de date GraphQL, ci implementează un UI optimist folosind o combinație de optimisticResponse și Actualizați.

Mutații, interogări și abonamente

Mutațiile, interogările și abonamentele reprezintă funcția de bază pentru integrarea cu API-ul GraphQL. În aplicația noastră, această funcție este implementată în Cities.js, City.js, și AddCity.js fișiere utilizând clientul AppSync.

Să examinăm mai atent cum sunt implementate mutații, interogări și abonamente în codul nostru.

Întrebări

În primul rând, să examinăm cum să creați și să exportați o interogare GraphQL care ar putea interacționa cu listCities interogare în schema noastră AppSync. Acest cod este conținut în src / interogări / ListCities.js fişier.

import gql de la 'graphql-tag'; export default gql 'lista de interogăriCities listCities items name country id' 

Apoi, vom importa această interogare în Cities.js fișier, împreună cu unii ajutoare de la reacționează-apollo, și sâmbăiți componenta pe care dorim să o accesăm la aceste date Compune și graphql din reacționează-apollo.

import compose, graphql de la import-ul "react-apollo" ListaCities din clasele "./queries/ListCities" extinde React.Component // definitia clasei aici // au acum acces la this.props.cities (orașele: props.data.listCities? props.data.listCities.items: [],))) (CityList)

Acum avem acces la seria de orașe de pe serverul GraphQL ca propunere. Putem folosi this.props.cities pentru a mapa peste matricea de orase care vine din GraphQL.

mutaţiile

Pentru a crea o mutație, mai întâi trebuie să creați o mutație de bază GraphQL și să o exportați. Noi facem asta în src / mutații / CreateCity.js fişier.

import gql de la 'graphql-tag' mutație implicită de export gql 'addCity ($ name: String !, $ country: String !, $ id: ID!) createCity : $ id) numele țării id ' 

Acum putem importa această mutație (împreună cu ajutorul lui Apollo) în AddCity.js fișier și utilizați-l într-o componentă: 

import compose, graphql din importul "react-apollo" import AddCityMutation din clasa './mutations/AddCity' AddCity extinde React.Component // definirea clasei aici // are acum acces la this.props.onAdd () compose (graphql (AddCityMutation, props: props => (onAdd: city => props.mutate (variables: city) 

Acum, avem acces la un plan numit onAdd, pe care trecem un obiect pe care dorim să-l trimitem mutației!

Abonamente

Abonamentele ne permit să ne abonați la modificările de date și să le actualizăm în aplicația noastră în timp real. Dacă ne-am schimba baza de date prin adăugarea sau eliminarea unui oraș, dorim ca aplicația noastră să se actualizeze în timp real.

În primul rând, trebuie să creați mutația și să o exportați, astfel încât să putem avea acces la ea în cadrul clientului. Salvăm acest lucru în src / subscriptionsNewCitySubscriptions.js fişier.

import gql de la 'graphql-tag' abonament implicit la exportul gql 'NewCitySub onCreateCity name country id'; 

Acum putem importa și atașa abonamentul în Cities.js. Ne-am uitat deja cum să obținem orașele din API-ul nostru. Să actualizăm acum această funcție pentru a vă abona la noi modificări și pentru a actualiza matricea orașelor când se adaugă un oraș nou.

importați AllCity din importul "./queries/AllCity" NewCitiesSubscrierea de la "./subscriptions/NewCitySubscription"; import compose, graphql din clasa "react-apollo" Cities extinde React.Component componentWillMount () this.props.subscribeToNewCities ();  render () // restul componentei aici export implicit compose (graphql (ListCities, opțiuni: fetchPolicy: 'cache-and-network', recuzită: (recuzită) => return. date.listCities?props.data.listCities.items: [], subscribeToNewCities: params => props.data.subscribeToMore (document: NewCitiesSubscription, updateQuery: (prev, subscriptionData: data: onCreateCity > return ... prev, listCities: __typename: 'CityConnection', elemente: [onCreateCity, ... prev.listCities.items.filter (oraș => city.id! == onCreateCity.id)]   ) )(Orase)

Adăugăm un nou model numit subscribeToNewCities, la care sunăm componentDidMount. În abonament, trecem într-un document (definiția abonamentului) și updateQuery pentru a descrie ce vrem să se întâmple când se actualizează acest lucru.

Distrugem createCity (conținând mutația) de la recuzita care sunt transmise în updateQuery funcția și returnează toate valorile existente împreună cu o actualizare listCities  array care conține orașele anterioare, împreună cu datele din noile orașe pe care le primim createCity.

Optimist UI

Dacă nu vrem să așteptăm ca abonamentul să returneze cele mai actualizate date din API-ul nostru pentru a ne actualiza interfața de utilizare?

Dacă un utilizator creează un oraș nou, dorim să îl adăugăm automat și să îl redăm în aplicația noastră înainte de a primi confirmarea de la serviciul back-end.

Putem face acest lucru cu ușurință folosind câteva tehnici și funcții.

Să ne actualizăm AddCityMutation la următoarele (puteți vedea acest cod în fișierul sursă AddCity.js):

import compose, graphql din importul "react-apollo" import AddCityMutation din clasa './mutations/AddCity' AddCity extinde React.Component // definirea clasei aici // are acum acces la this.props.onAdd () compose (graphql (AddCityMutation, props: props => (onAdd: city => props.mutate variables: city, optimisticResponse: __typename: 'Mutation', createCity: ... city, __typename: 'City' , actualizați: (proxy, date: createCity) => const data = proxy.readQuery (query: ListCities); , date);)))) (AddCity) 

Aici am adăugat două proprietăți noi în obiectul argumentului funcției mutate:

  1. optimisticResponse definește noul răspuns pe care doriți să îl aveți disponibil în funcția de actualizare.
  2. Actualizați ia două argumente, proxy-ul (care vă permite să citiți din memoria cache) și datele pe care doriți să le utilizați pentru a face actualizarea. Am citit cache-ul curent (proxy.readQuery), adăugați elementul nostru nou la gama de articole și apoi scrieți înapoi în memoria cache, care a actualizat interfața noastră utilizator.

Concluzie

GraphQL devine din ce în ce mai importantă. O mare parte din complexitatea din jurul GraphQL are de a face cu gestionarea back end și a stratului API. Cu toate acestea, unelte precum AppSync abate această complexitate, eliberând dezvoltatorii de la petrecerea majorității timpului de configurare și de lucru pe server.

Aștept cu nerăbdare mult mai multe inovații în acest spațiu și nu pot să aștept să văd ce altceva vom vedea în 2018!

Dacă sunteți interesat să utilizați AppSync împreună cu cadrul fără server, verificați această minunată introducere în utilizarea celor două împreună.

Dacă doriți să aflați mai multe despre AWS AppSync, aș sugera să aruncați o privire la pagina de pornire AppSync și la documentația pentru construirea unui client GraphQL.

Dacă doriți să contribuiți la acest proiect, vă puteți conecta la repo GitHub. Dacă aveți idei, nu ezitați să ne trimiteți un PR sau să utilizați această aplicație ca starter pentru următorul proiect React Native GraphQL!

Și între timp, verificați câteva dintre celelalte tutoriale de la React Native aici pe Envato Tuts+!

Cod