GraphQL-Clients mit React und Apollo, Teil 2

React, Apollo, TypeScript: Drei zeitgemäße Techniken, um die im ersten Teil entwickelte Java-Anwendung auf Clientseite umzumünzen.

Werkzeuge  –  0 Kommentare
GraphQL-Clients mit React und Apollo, Teil 2

Der erste Teil der Artikelserie beschäftigte sich mit der Frage, wie sich mit Java GraphQL-Schnittstellen für serverseitige Anwendungen entwickeln lassen. Der zweite Beitrag zeigt, wie Entwickler einen Client für die API mit React und dem Apollo-Framework bauen können. Darüber hinaus kommt TypeScript bei der Entwicklung zum Einsatz, um die Vorzüge typsicherer Entwicklung nutzen zu können.

Die Einstiegsseite der Anwendung zeigt eine Liste der bekannten Biere an (Abb. 1).

Ein einfacher GraphQL-Client

GraphQL-Abfragen werden überlichweise per HTTP Post Request an den Server geschickt. Die Abfrage (die GraphQL Query) als auch die Variablen dafür werden als Payload übergeben. Mit der fetch-API lassen sich somit einfach React-Komponenten bauen, die Daten von einer GraphQL-Schnittstelle abfragen und anzeigen. Das folgende Beispiel bedient sich der im ersten Teil der Serie vorgestellten BeerAdvisor-Anwendung, die auf GitHub zu finden ist.

Die Komponente führt eine Query aus, die die Daten für die Einstiegsseite der Anwendung lädt – eine Übersicht über alle im System vorhandenen Biere.

const QUERY = `
query BeerOverviewPageQuery {
beers {
id name averageStars
}
}
`;

class BeerOverviewPage extends React.Component {
state = {};

async componentDidMount() {
const response = await fetch("http://localhost:9000/graphql", {
method: "POST",
body: JSON.stringify({ query: QUERY })
});

const graphqlResult = await response.json();
this.setState({ beers: graphqlResult.data });
}

render() {
if (!this.state.beers) {
return <h1>Beers not loaded yet...</h1>;
}

return . . .; // Biere (this.state.beers) hier rendern
}
}

Sobald React die Komponente in den DOM gehängt hat, führt sie die definierte GraphQL Query aus. Das ist ein gängiges Muster beim Arbeiten mit jeglicher Art von asynchronen Daten in React. Sobald das Ergebnis geladen ist, setzt die Anwendung es in den State und rendert die Komponente neu. Die render-Methode kann die geladenen Daten nun anzeigen. Ruft React die Methode beim erstmaligen Rendern noch ohne die geladenen Daten auf, zeigt die Komponente einen Hinweis für den Benutzer an, das die Daten noch geladen werden. Auch das ist ein gewöhnliches Pattern in React-Anwendungen.

Obwohl die gezeigte Komponente funktioniert, fehlen ihr eine ganze Reihe Features, die eine Anwendung üblicherweise benötigt. Es gibt keinen Lebenszyklus des Requests (1. Request ist abgeschickt beziehungsweise wartet auf Antwort, 2. Daten sind erfolgreich geladen oder 3. es ist ein Fehler aufgetreten). Außerdem erhalten die geladenen Daten auch kein Caching außerhalb des UI. Wenn Anwender sich durch die App navigieren und dadurch die Komponente aus- und wieder einblenden, führt sie den Request beim erneuten Anzeigen der Komponente jedes Mal aus. Das kann zwar gewünschtes Verhalten sein, aber es gibt auch Fälle, in denen das nicht richtig ist und die Applikation die bereits geladenen Daten zeigen soll.

Eventuell benötigen Entwickler auch eine Mischung aus beiden Ansätzen. Zunächst zeigt die Applikation die geladenen Daten an, im Hintergrund läuft die Query aber erneut und aktualisiert mit Eintreffen des Ergebnisses die Daten in der UI. Oder es kann für die Anwendung relevant sein, dass sie die angezeigten Daten sogar dann aktualisiert, wenn der Anwender die Seite gar nicht verlässt.

Die Liste der Bewertungen eines Biers etwa wird automatisch aktualisiert, sobald eine neue Bewertung für das gerade angezeigte Bier auf dem Server eingegangen ist, ohne dass der Besucher der Seite etwas dafür tun müsste. Das ist von der gezeigten Beispiel-Komponente nicht implementiert. Wenn es sich um einen schreibenden Zugriff, also eine Mutation, handelt, kommen noch weitere Fragestellungen hinzu (etwa wie der Umgang mit dem Ergebnis der Mutation aussieht), sodass die aktualisierten Daten vom Server anwendungsweit konsistent aktualisiert dargestellt werden.