Codeer een app met GraphQL, React Native en AWS AppSync de app

Wat je gaat creëren

In deze zelfstudies laat ik u zien hoe u een GraphQL-database kunt maken en ermee kunt werken met behulp van AWS AppSync en React Native. Deze app heeft real-time en offline functionaliteit, iets wat we uit de doos halen met AppSync. 

In het vorige bericht hebben we onze GraphQL-back-end ingesteld met de Amazon AppSync-service. Bekijk het als je dat nog niet hebt gedaan. Of, als u een inleiding tot GraphQL wilt, kijk eens naar enkele van onze andere berichten.

In dit bericht zullen we alles inpakken door de build van de React Native-client te doorlopen. Het project is een beetje te ingewikkeld om je stap voor stap bij te staan, maar ik zal de projectarchitectuur uitleggen en de belangrijkste delen van de broncode tonen.

Overzicht van de app-architectuur en mappenstructuur

Onze applicatie heeft een centraal toegangspunt dat zal bestaan ​​uit twee weergaven met tabbladen. Eén tabblad geeft een overzicht van de steden uit onze GraphQL-database en de andere is het invoerformulier om een ​​nieuwe stad toe te voegen. De Cities tabblad is een navigator waarmee de gebruiker naar de afzonderlijke steden kan navigeren.

We slaan de belangrijkste componenten op in de bron map en heeft andere mappen in de map src directory om onze GraphQL-mutaties, -query's en -abonnementen bij te houden.

We zullen ook een middelen map om onze afbeeldingen te bewaren.

Maken en configureren van de Reactieve klant

Ter referentie, bekijk de definitieve code voor deze app in de tutorial GitHub repo, maar ik zal enkele stappen beschrijven die ik heb genomen om de app helemaal opnieuw te maken.

Eerst hebben we een nieuwe React Native-toepassing gemaakt met Expo. 

Eenmaal in het nieuw gecreëerde project hebben we onze afhankelijkheden geïnstalleerd. Voor de functies GraphQL en AppSync hebben we de volgende afhankelijkheden gebruikt:

aws-appsync aws-appsync-react graphql-tag react-apollo uuid

We gebruikten ook de volgende afhankelijkheden voor het UI-ontwerp:

react-navigation react-native-elements react-native-vector-icons

Nadat de Vector Icons-bibliotheek was geïnstalleerd, hebben we deze ook gekoppeld:

react-native link react-native vector-icons

Na het installeren van onze afhankelijkheden hebben we het AppSync.js bestand van onze AppSync-console. In onze AppSync-projectconsole hebben we gekozen Reageer Native onderaan en klikte op de sinaasappel Download om dit configuratiebestand te downloaden.


Dit configuratiebestand bevat de AppSync-clientinformatie die we nodig hebben om een ​​nieuwe client te maken. 

Configuratie van de aanbieder en winkel

Op het hoogste niveau van de app zullen we onze configuratie uitvoeren om de AppSync API met de React Native-client te verbinden.Als je Redux of React Apollo eerder hebt gebruikt, is dit allemaal vertrouwd. Als je dat nog niet hebt gedaan, onthoud dan dat elk kind van een leverancier, in ons geval de ApolloProvider, zal toegang hebben tot de gegeven functionaliteit. 

De volgende code is onze nieuwe App.js bestand, het hoofdbestanddeel dat wordt geïmporteerd uit onze index.js ingangspunt.

import Reageren van 'reageren' Tabbladen importeren vanuit './src/Tabs' import AWSAppSyncClient van "aws-appsync"; import Rehydrated uit 'aws-appsync-react'; importeer ApolloProvider van 'react-apollo'; importeer appSyncConfig van './aws-exports'; const client = nieuwe AWSAppSyncClient (url: appSyncConfig.graphqlEndpoint, region: appSyncConfig.region, auth: type: appSyncConfig.authType, apiKey: appSyncConfig.apiKey,); const WithProvider = () => (      ); standaard exporteren met Provider

In dit bestand stellen we een nieuwe AppSync-client in met behulp van een combinatie van de AWSAppSyncClient constructor van AWS-AppSync evenals de configuratie in onze AWS-exports.js bestand, dat de GraphQL API-URL, regio, verificatietype en verificatie API-sleutel biedt.

Vervolgens verpakken we ons hoofd-entrypoint, de Tabs.js bestand dat onze tabnavigatie zal behouden, in een ApolloProvider en geef de AppSync-client door als clientprop. We verpakken ook de tabs component in a gerehydrateerd component die we importeren aws-AppSync reageren. Dit zorgt ervoor dat we asynchrone opslag hebben gelezen en onze cache opnieuw hebben gehydrateerd voordat de gebruikersinterface wordt weergegeven.

Nu kan onze app gegevens opvragen uit ons AppSync-eindpunt en mutaties en abonnementen uitvoeren!

Navigatie

Het belangrijkste startpunt van de app is een navigatie met tabbladen, geïmplementeerd in het bestand Tabs.js met React Navigation.

Wat we hier hebben gedaan, is het maken en exporteren van een TabNavigator met twee tabbladen. Dit zijn:

  1. Cities: Dit onderdeel geeft een overzicht van onze steden en is een navigatorcomponent op zich. Dit onderdeel is een navigator omdat we naar elke afzonderlijke stad willen kunnen navigeren en de locaties in de stad kunnen bekijken.
  2. AddCity: Dit onderdeel is een formulier voor ons om nieuwe steden toe te voegen.

Herbruikbare componenten

Deze app heeft slechts één herbruikbaar onderdeel, een aangepast Tekst invoer. Omdat we deze stijl en functionaliteit keer op keer dupliceren, hebben we besloten om er een eigen component van te maken. De invoercomponent is geïmplementeerd in Input.js.

Stedenlijst en stadsnavigatie

Het belangrijkste beeld van de app is een lijst met steden die we van GraphQL zullen ophalen. We willen kunnen navigeren van elke beursgenoteerde stad naar een detailoverzicht van die stad waar we locaties kunnen toevoegen.

Om dit te doen, maken we Cities.js zijn eigen StackNavigator, en City.js de component waarnaar we navigeren bij het kiezen van een stad. Klikken op een stad in Cities, we geven zijn naam en id door als rekwisieten stad.

Cities.js

In deze component halen we het gebruik van de listCities query, en we zijn ook geabonneerd op de NewCitySubscription, zodat wanneer een nieuwe stad wordt toegevoegd, zelfs van een andere klant, we dat abonnement afhandelen en onze reeks steden bijwerken. De listCities query maakt een reeks steden beschikbaar in onze component als this.props.cities.

City.js

In dit onderdeel zijn we een stad gepasseerd als rekwisieten van navigatie (beschikbaar als props.navigation.state.params.city). We gebruiken de stad ID kaart waarde om de lijst met locaties voor de gekozen stad op te halen met behulp van de listLocations query. We abonneren op nieuwe locaties op dezelfde manier als waarop we geabonneerd zijn op nieuwe steden in Cities.js, de ... gebruiken NewLocationSubscription abonnement. We bieden ook optimisticResponse en bijwerken functies voor wanneer een nieuwe stad wordt toegevoegd. 

Steden toevoegen

Ten slotte moeten we de functionaliteit implementeren voor het toevoegen van nieuwe steden aan onze GraphQL API in het AddCity.js-bestand. Om dit te doen, hebben we een mutatie gekoppeld, samen met een formulier dat zal bellen createCity, de waarde van de formulierinvoer doorgeven.

AddCity heeft een onAdd functie die we definiëren in onze GraphQL-compositie, die niet alleen een nieuwe stad naar onze GraphQL-database schrijft, maar ook een optimistische UI implementeert met een combinatie van optimisticResponse en bijwerken.

Mutaties, query's en abonnementen

Mutaties, query's en abonnementen zijn de kernfunctionaliteit voor integratie met onze GraphQL API. In onze app is deze functionaliteit geïmplementeerd in de Cities.js, City.js, en AddCity.js bestanden met behulp van de AppSync-client.

Laten we eens nader bekijken hoe mutaties, query's en abonnementen in onze code zijn geïmplementeerd.

queries

Laten we eerst kijken hoe een GraphQL-query kan worden gemaakt en geëxporteerd die kan interageren met de listCities query in onze AppSync Schema. Deze code bevindt zich in de src / queries / ListCities.js het dossier.

importeer gql van 'graphql-tag'; exporteer standaard gql 'query listCities listCities items naam land id' 

Vervolgens importeren we deze query in de Cities.js bestand, samen met enkele helpers van reactie-apollo, en bedraad de component die we graag toegang zouden willen hebben tot deze gegevens met componeren en graphql van reactie-apollo.

importeer compose, graphql van 'react-apollo' import ListCities van './queries/ListCities' class Cities breidt React.Component uit // class definition here // heb nu toegang tot this.props.cities export standaard opstellen ( graphql (ListCities, props: props => (cities: props.data.listCities? props.data.listCities.items: [],))) (CityList)

Nu hebben we toegang tot de array cities van onze GraphQL-server als een prop. We kunnen gebruiken this.props.cities om in te delen in de array van de steden die afkomstig zijn van GraphQL.

mutaties

Om een ​​mutatie aan te maken, moeten we eerst een eenvoudige GraphQL-mutatie maken en deze exporteren. We doen dit in de src / mutaties / CreateCity.js het dossier.

import gql van 'graphql-tag' export standaard gql 'mutatie addCity ($ naam: String !, $ land: String !, $ id: ID!) createCity (invoer: naam: $ naam, land: $ land, id : $ id) naam land id ' 

Nu kunnen we deze mutatie importeren (samen met de Apollo-helpers) in de AddCity.js bestand en gebruik het in een component: 

importeer compose, graphql van 'react-apollo' importeer AddCityMutation van './mutations/AddCity' class AddCity breidt React.Component // class definition here // nu toegang tot this.props.onAdd () exporteer standaard compose (graphql (AddCityMutation, props: props => (onAdd: city => props.mutate (variables: city)))) (AddCity) 

Nu hebben we toegang tot een opgeroepen prop onAdd, waarmee we een object doorgeven dat we naar de mutatie willen sturen!

abonnementen

Met abonnementen kunnen we ons abonneren op gegevenswijzigingen en ze in realtime bijwerken in onze applicatie. Als we onze database willen wijzigen door een stad toe te voegen of te verwijderen, willen we graag dat onze app in realtime wordt bijgewerkt.

Ten eerste moeten we de mutatie maken en deze exporteren, zodat we er binnen de klant toegang toe hebben. We bewaren dit in de src / subscriptionsNewCitySubscriptions.js het dossier.

importeer gql van 'graphql-tag' export standaard gql 'abonnement NewCitySub onCreateCity naam land id'; 

Nu kunnen we het abonnement importeren en toevoegen in Cities.js. We hebben al gekeken hoe we de steden uit onze API kunnen halen. Laten we deze functionaliteit nu bijwerken om zich te abonneren op nieuwe wijzigingen en de stedenarray bijwerken wanneer een nieuwe stad wordt toegevoegd.

importeer AllCity van './queries/AllCity' importeer NewCitiesSubscription from './subscriptions/NewCitySubscription'; import compose, graphql van 'react-apollo' class Cities breidt React.Component uit componentWillMount () this.props.subscribeToNewCities ();  render () // rest van het onderdeel hier exporteer standaard compose (graphql (ListCities, options: fetchPolicy: 'cache-and-network', props: (props) => return cities: props. data.listCities? props.data.listCities.items: [], subscribeToNewCities: params => props.data.subscribeToMore (document: NewCitiesSubscription, updateQuery: (vorige, subscriptionData: data: onCreateCity) = > return ... vorige, lijstCities: __typename: 'CityConnection', items: [onCreateCity, ... vorig.listCities.items.filter (city => city.id! == onCreateCity.id)]) )) (Steden)

We voegen een nieuwe prop toe genaamd subscribeToNewCities, waarin we bellen componentDidMount. In het abonnement geven we een document door (de abonnementdefinitie) en updateQuery om te beschrijven wat we willen doen wanneer deze updates.

We destructure createCity (met de mutatie) van de rekwisieten die in de updateQuery functie en retourneer alle bestaande waarden samen met een bijgewerkte listCities  array met de vorige steden samen met de nieuwe stadsgegevens die we ontvangen createCity.

Optimistische gebruikersinterface

Wat als we niet willen wachten op het abonnement om de meest actuele gegevens van onze API te retourneren om onze gebruikersinterface te updaten?

Als een gebruiker een nieuwe stad maakt, willen we deze automatisch de stedenarray toevoegen en deze in onze app renderen voordat de bevestiging van de back-endservice wordt ontvangen.

We kunnen dat eenvoudig doen met behulp van een paar technieken en functies.

Laten we onze updaten AddCityMutation naar het volgende (u kunt deze code bekijken in het bronbestand van AddCity.js):

importeer compose, graphql van 'react-apollo' importeer AddCityMutation van './mutations/AddCity' class AddCity breidt React.Component // class definition here // nu toegang tot this.props.onAdd () exporteer standaard compose (graphql (AddCityMutation, props: props => (onAdd: city => props.mutate (variables: city, optimisticResponse: __typename: 'Mutation', createCity: ... city, __typename: 'City' , update: (proxy, data: createCity) => const data = proxy.readQuery (query: ListCities); data.listCities.items.unshift (createCity); proxy.writeQuery (query: ListCities , data);)))) (AddCity) 

Hier hebben we twee nieuwe eigenschappen aan het argument object mutate function toegevoegd:

  1. optimisticResponse definieert het nieuwe antwoord dat u beschikbaar zou willen hebben in de updatefunctie.
  2. bijwerken neemt twee argumenten, de proxy (waarmee u uit de cache kunt lezen) en de gegevens die u wilt gebruiken om de update te maken. We lezen de huidige cache (proxy.readQuery), voeg het ons nieuwe item toe aan de reeks items en schrijf vervolgens terug naar de cache, die onze gebruikersinterface heeft bijgewerkt.

Conclusie

GraphQL wordt meer en meer mainstream. Veel van de complexiteit rondom GraphQL heeft te maken met het beheer van de back-end en de API-laag. Tools zoals AppSync abstraheren echter deze complexiteit, waardoor ontwikkelaars de meeste tijd kwijt zijn met het configureren en werken op de server.

Ik kijk uit naar veel meer innovatie in deze ruimte en kan niet wachten om te zien wat we nog meer zullen zien in 2018!

Als u geïnteresseerd bent in het gebruik van AppSync samen met het Serverless-framework, bekijk dan deze geweldige introductie tot het gebruik van deze twee samen.

Als u meer wilt weten over AWS AppSync, zou ik een kijkje willen nemen op de AppSync startpagina en de documentatie voor het bouwen van een GraphQL-client..

Als je een bijdrage wilt leveren aan dit project, kun je verbinding maken met onze GitHub-repo. Als u ideeën heeft, kunt u ons een PR sturen of deze app gebruiken als starter voor uw volgende React Native GraphQL-project!

En bekijk in de tussentijd enkele van onze andere handleidingen over React Native hier op Envato Tuts+!