Catégories
Astuces et Design

Comprendre GraphQl côté client avec Apollo-Client dans React Apps – Smashing Magazine

A propos de l'auteur

Blessing Krofegha est un ingénieur logiciel basé à Lagos au Nigeria, avec un désir ardent de contribuer à rendre le Web génial pour tous, en écrivant et en construisant…
Plus à propos
Bénédiction

Avez-vous déjà essayé d'interagir avec un serveur GraphQL dans une application côté client et avez-vous envie d'abandonner avant même de vous rendre quelque part? Avez-vous déjà refusé une invitation à rejoindre une base de code qui nécessite de travailler avec l'API GraphQL parce que vous n'en aviez aucune idée? Vous êtes-vous déjà senti comme le seul ingénieur front-end à ne pas avoir appris à utiliser les API GraphQL? Si vous avez répondu oui à l'une de ces questions, ce didacticiel est fait pour vous. Nous allons examiner de plus près quelques bases de GraphQL et Apollo Client, ainsi que la façon de travailler avec les deux. À la fin, nous aurons créé une application pour animalerie qui utilise Apollo Client. Ensuite, vous pouvez continuer à créer votre prochain projet.

Selon State of JavaScript 2019, 38,7% des développeurs aimeraient utiliser GraphQL, tandis que 50,8% des développeurs aimeraient apprendre GraphQL.

En tant que langage de requête, GraphQL simplifie le flux de travail de création d'une application client. Il supprime la complexité de la gestion des points de terminaison d'API dans les applications côté client, car il expose un seul point de terminaison HTTP pour récupérer les données requises. Par conséquent, il élimine la surextraction et la sous-extraction des données, comme dans le cas de REST.

Mais GraphQL n'est qu'un langage de requête. Pour l'utiliser facilement, nous avons besoin d'une plate-forme qui fait le gros du travail à notre place. L'une de ces plates-formes est Apollo.

La plateforme Apollo est une implémentation de GraphQL qui transfère des données entre le cloud (le serveur) vers l'interface utilisateur de votre application. Lorsque vous utilisez Apollo Client, toute la logique de récupération des données, de suivi, de chargement et de mise à jour de l'interface utilisateur est encapsulée par le useQuery hook (comme dans le cas de React). Par conséquent, la récupération des données est déclarative. Il a également une mise en cache sans configuration. En configurant simplement Apollo Client dans votre application, vous obtenez un cache intelligent prêt à l'emploi, sans configuration supplémentaire requise.

Apollo Client est également interopérable avec d'autres frameworks, tels que Angular, Vue.js et React.

Remarque: Ce tutoriel profitera à ceux qui ont travaillé avec RESTful ou d'autres formes d'API dans le passé côté client et veulent voir si GraphQL vaut la peine d'être essayé. Cela signifie que vous devriez avoir déjà travaillé avec une API; ce n'est qu'alors que vous pourrez comprendre à quel point GraphQL pourrait vous être bénéfique. Bien que nous couvrions quelques bases de GraphQL et d'Apollo Client, une bonne connaissance de JavaScript et React Hooks sera utile.

Bases de GraphQL

Cet article n'est pas un introduction complète à GraphQL, mais nous définirons quelques conventions avant de continuer.

Qu'est-ce que GraphQL?

GraphQL est une spécification qui décrit un langage de requête déclaratif que vos clients peuvent utiliser pour demander à une API les données exactes qu'ils souhaitent. Ceci est réalisé en créant un schéma de type fort pour votre API, avec une flexibilité ultime. Cela garantit également que l'API résout les données et que les requêtes des clients sont validées par rapport à un schéma. Cette définition signifie que GraphQL contient des spécifications qui en font un langage de requête déclaratif, avec une API typée statiquement (construite autour de Typescript) et permettant au client d'exploiter ces systèmes de types pour demander à l'API les données exactes qu'il souhaite .

Donc, si nous avons créé certains types avec des champs, alors, du côté client, nous pourrions dire: «Donnez-nous ces données avec ces champs exacts». Ensuite, l'API répondra avec cette forme exacte, comme si nous utilisions un système de type dans un langage fortement typé. Vous pouvez en savoir plus dans mon article Typescript.

Examinons quelques conventions de GraphQl qui nous aideront à continuer.

Les bases

  • Opérations
    Dans GraphQL, chaque action effectuée est appelée une opération. Il y a quelques opérations, à savoir:
    • Requete
      Cette opération concerne la récupération des données du serveur. Vous pouvez également appeler cela une extraction en lecture seule.
    • Mutation
      Cette opération implique la création, la mise à jour et la suppression de données d'un serveur. Elle est communément appelée une opération CUD (création, mise à jour et suppression).
    • Abonnements
      Cette opération dans GraphQL consiste à envoyer des données d'un serveur à ses clients lorsque des événements spécifiques se produisent. Ils sont généralement implémentés avec WebSockets.

Dans cet article, nous ne traiterons que des opérations de requête et de mutation.

  • Opération des noms
    Il y a unique des noms pour vos opérations de requête et de mutation côté client.
  • Variables et arguments
    Les opérations peuvent définir des arguments, tout comme une fonction dans la plupart des langages de programmation. Ces variables peuvent ensuite être transmises à des appels de requête ou de mutation à l'intérieur de l'opération en tant qu'arguments. Les variables doivent être fournies au moment de l'exécution pendant l'exécution d'une opération à partir de votre client.
  • Aliasing
    Il s'agit d'une convention dans GraphQL côté client qui consiste à renommer les noms de champ verbeux ou vagues avec des noms de champ simples et lisibles pour l'interface utilisateur. Les alias sont nécessaires dans les cas d’utilisation où vous ne souhaitez pas avoir de noms de champ en conflit.
Conventions de base GraphQL
Conventions de base de GraphQL. (Grand aperçu)

Qu'est-ce que GraphQL côté client?

Lorsqu'un ingénieur frontal crée des composants d'interface utilisateur en utilisant n'importe quel framework, comme Vue.js ou (dans notre cas) React, ces composants sont modélisés et conçus à partir d'un certain modèle sur le client pour s'adapter aux données qui seront extraites du serveur.

L'un des problèmes les plus courants avec les API RESTful est la surexploitation et la sous-extraction. Cela se produit car le seul moyen pour un client de télécharger des données est de toucher les points de terminaison qui retournent fixé structures de données. Surcharge dans ce contexte, cela signifie qu'un client télécharge plus d'informations que ce qui est requis par l'application.

Dans GraphQL, en revanche, vous envoyez simplement une seule requête au serveur GraphQL qui inclut les données requises. Le serveur répondrait alors avec un objet JSON contenant les données exactes que vous avez demandées, donc pas de surextraction. Sebastian Eschweiler explique les différences entre les API RESTful et GraphQL.

GraphQL côté client est une infrastructure côté client qui s'interface avec les données d'un serveur GraphQL pour exécuter les fonctions suivantes:

  • Il gère les données en envoyant des requêtes et en mutant les données sans que vous ayez à construire vous-même des requêtes HTTP. Vous pouvez passer moins de temps à analyser les données et plus de temps à créer l'application réelle.
  • Il gère pour vous la complexité d'un cache. Ainsi, vous pouvez stocker et récupérer les données récupérées sur le serveur, sans aucune interférence de tiers, et éviter facilement de récupérer les ressources en double. Ainsi, il identifie lorsque deux ressources sont identiques, ce qui est idéal pour une application complexe.
  • Il maintient votre interface utilisateur cohérente avec l'interface utilisateur optimiste, une convention qui simule les résultats d'une mutation (c'est-à-dire les données créées) et met à jour l'interface utilisateur avant même de recevoir une réponse du serveur. Une fois la réponse reçue du serveur, le résultat optimiste est rejeté et remplacé par le résultat réel.

Pour plus d'informations sur GraphQL côté client, épargnez une heure avec le cocréateur de GraphQL et d'autres personnes sympas sur GraphQL Radio.

Qu'est-ce que Apollo Client?

Apollo Client est un client GraphQL interopérable, ultra-flexible et axé sur la communauté pour JavaScript et les plates-formes natives. Ses fonctionnalités impressionnantes incluent un outil de gestion d'état robuste (Apollo Link), un système de mise en cache sans configuration, une approche déclarative de la récupération des données, une pagination facile à mettre en œuvre et l'interface utilisateur optimiste pour votre application côté client.

Apollo Client stocke non seulement l'état des données extraites du serveur, mais également l'état qu'il a créé localement sur votre client; par conséquent, il gère l'état des données API et des données locales.

Il est également important de noter que vous pouvez utiliser Apollo Client avec d’autres outils de gestion d’états, comme Redux, sans conflit. De plus, il est possible de migrer la gestion de l’état de, par exemple, Redux vers Apollo Client (ce qui dépasse le cadre de cet article). En fin de compte, l'objectif principal d'Apollo Client est de permettre aux ingénieurs d'interroger les données d'une API de manière transparente.

Caractéristiques d'Apollo Client

Apollo Client a convaincu de nombreux ingénieurs et entreprises en raison de ses fonctionnalités extrêmement utiles qui facilitent la création d'applications modernes et robustes. Les caractéristiques suivantes sont intégrées:

  • Mise en cache
    Apollo Client prend en charge la mise en cache à la volée.
  • Interface utilisateur optimiste
    Apollo Client a un support sympa pour l'interface utilisateur optimiste. Il s'agit d'afficher temporairement l'état final d'une opération (mutation) pendant que l'opération est en cours. Une fois l'opération terminée, les données réelles remplacent les données optimistes.
  • Pagination
    Apollo Client a une fonctionnalité intégrée qui facilite la mise en œuvre de la pagination dans votre application. Il prend en charge la plupart des maux de tête techniques liés à la récupération d'une liste de données, soit sous forme de correctifs, soit en une seule fois, en utilisant le fetchMore fonction, qui vient avec le useQuery crochet.

Dans cet article, nous examinerons une sélection de ces fonctionnalités.

Assez de théorie. Serrez votre ceinture de sécurité et prenez une tasse de café pour accompagner vos crêpes, car nous nous salissons les mains.

Construire notre application Web

Ce projet est inspiré de Scott Moss.

Nous allons créer une application Web simple pour animalerie, dont les fonctionnalités incluent:

  • récupérer nos animaux de compagnie du côté serveur;
  • créer un animal de compagnie (ce qui implique la création du nom, du type d'animal de compagnie et de l'image);
  • en utilisant l'interface optimiste;
  • en utilisant la pagination pour segmenter nos données.

Pour commencer, clonez le référentiel en vous assurant que le starter branche est ce que vous avez cloné.

Commencer
  • Installez l'extension Apollo Client Developer Tools pour Chrome.
  • À l'aide de l'interface de ligne de commande (CLI), accédez au répertoire du référentiel cloné et exécutez la commande pour obtenir toutes les dépendances: npm install.
  • Exécutez la commande npm run app pour démarrer l'application.
  • Alors que toujours dans le dossier racine, exécutez la commande npm run server. Cela démarrera notre serveur back-end pour nous, que nous utiliserons au fur et à mesure.

L'application doit s'ouvrir dans un port configuré. Le mien est http://localhost:1234/; le vôtre est probablement autre chose.

Si tout a bien fonctionné, votre application devrait ressembler à ceci:

Interface utilisateur de la branche de démarrage clonée
Interface utilisateur de branche de démarrage clonée. (Grand aperçu)

Vous remarquerez que nous n'avons aucun animal à afficher. C'est parce que nous n'avons pas encore créé de telles fonctionnalités.

Si vous avez correctement installé Apollo Client Developer Tools, ouvrez les outils de développement et cliquez sur l'icône de la barre d'état. Vous verrez "Apollo" et quelque chose comme ceci:

Outils de développement client Apollo
Outils de développement client Apollo. (Grand aperçu)

Comme les outils de développement Redux et React, nous utiliserons Apollo Client Developer Tools pour écrire et tester nos requêtes et mutations. L'extension est fournie avec le GraphQL Playground.

Aller chercher des animaux

Ajoutons la fonctionnalité qui récupère les animaux de compagnie. Passer à client/src/client.js. Nous allons écrire Apollo Client, le lier à une API, l'exporter en tant que client par défaut et écrire une nouvelle requête.

Copiez le code suivant et collez-le dans client.js:

import { ApolloClient } from 'apollo-client'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { HttpLink } from 'apollo-link-http'

const link = new HttpLink({ uri: 'https://localhost:4000/' })
const cache = new InMemoryCache()
const client = new ApolloClient({
  link,
  cache
})
export default client

Voici une explication de ce qui se passe ci-dessus:

  • ApolloClient
    Ce sera la fonction qui enveloppe notre application et, par conséquent, s'interface avec HTTP, met en cache les données et met à jour l'interface utilisateur.
  • InMemoryCache
    Il s'agit du magasin de données normalisé dans Apollo Client qui aide à manipuler le cache dans notre application.
  • HttpLink
    Il s'agit d'une interface réseau standard permettant de modifier le flux de contrôle des requêtes GraphQL et de récupérer les résultats GraphQL. Il agit comme un middleware, récupérant les résultats du serveur GraphQL à chaque fois que le lien est déclenché. De plus, c'est un bon substitut à d'autres options, comme Axios et window.fetch.
  • Nous déclarons une variable de lien affectée à une instance de HttpLink. Il faut un uri propriété et une valeur à notre serveur, qui est https://localhost:4000/.
  • Vient ensuite une variable de cache qui contient la nouvelle instance de InMemoryCache.
  • La variable client prend également une instance de ApolloClient et enveloppe le link et cache.
  • Enfin, nous exportons le client afin que nous puissions l'utiliser dans toute l'application.

Avant de voir cela en action, nous devons nous assurer que toute notre application est exposée à Apollo et que notre application peut recevoir des données extraites du serveur et qu'elle peut muter ces données.

Pour y parvenir, passons à client/src/index.js:

import React from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter } from 'react-router-dom'
import { ApolloProvider } from '@apollo/react-hooks'
import App from './components/App'
import client from './client'
import './index.css'
const Root = () => (
  
    
      
    
  
);
ReactDOM.render(, document.getElementById('app'))
if (module.hot) {
  module.hot.accept()
}

Comme vous le remarquerez dans le code en surbrillance, nous avons encapsulé le App composant dans ApolloProvider et a passé le client comme accessoire au client. ApolloProvider est similaire à React Context.Provider. Il enveloppe votre application React et place le client dans son contexte, ce qui vous permet d'y accéder depuis n'importe où dans votre arborescence de composants.

Pour récupérer nos animaux de compagnie sur le serveur, nous devons écrire des requêtes qui demandent le champs exacts que nous voulons. Dirigez-vous vers client/src/pages/Pets.jset copiez-collez-y le code suivant:

import React, {useState} from 'react'
import gql from 'graphql-tag'
import { useQuery, useMutation } from '@apollo/react-hooks'
import PetsList from '../components/PetsList'
import NewPetModal from '../components/NewPetModal'
import Loader from '../components/Loader'

const GET_PETS = gql`
  query getPets {
    pets {
      id
      name
      type
      img
    }
  }
`;

export default function Pets () {
  const (modal, setModal) = useState(false)
  const { loading, error, data } = useQuery(GET_PETS);

  if (loading) return ;

  if (error) return 

An error occured!

;
const onSubmit = input => { setModal(false) } if (modal) { return setModal(false)} /> } return (

Pets

) }

Avec quelques bits de code, nous pouvons récupérer les animaux de compagnie sur le serveur.

Qu'est-ce que gql?

Il est important de noter que les opérations dans GraphQL sont généralement des objets JSON écrits avec graphql-tag et avec des backticks.

gql Les balises sont des balises littérales de modèle JavaScript qui analysent les chaînes de requête GraphQL dans le GraphQL AST (arbre de syntaxe abstraite).

  • Opérations de requête
    Afin de récupérer nos animaux de compagnie sur le serveur, nous devons effectuer une opération de requête.
    • Parce que nous faisons un query opération, nous devions spécifier le type de fonctionnement avant de le nommer.
    • Le nom de notre requête est GET_PETS. C'est une convention de dénomination de GraphQL d'utiliser camelCase pour les noms de champ.
    • Le nom de nos champs est pets. Par conséquent, nous spécifions les champs exacts dont nous avons besoin du serveur (id, name, type, img).
    • useQuery est un hook React qui sert de base à l'exécution de requêtes dans une application Apollo. Pour effectuer une opération de requête dans notre composant React, nous appelons le useQuery hook, initialement importé de @apollo/react-hooks. Ensuite, nous lui passons une chaîne de requête GraphQL, qui est GET_PETS dans notre cas.
  • Lorsque notre composant est rendu, useQuery renvoie une réponse d'objet d'Apollo Client qui contient des propriétés de chargement, d'erreur et de données. Ainsi, ils sont déstructurés, afin que nous puissions les utiliser pour rendre l'interface utilisateur.
  • useQuery est génial. Nous n'avons pas à inclure async-await. Il est déjà pris en charge en arrière-plan. Assez cool, non?
    • loading
      Cette propriété nous aide à gérer l'état de chargement de l'application. Dans notre cas, nous retournons un Loader composant pendant que notre application se charge. Par défaut, le chargement est false.
    • error
      Au cas où, nous utilisons cette propriété pour gérer toute erreur qui pourrait survenir.
    • data
      Celui-ci contient nos données réelles du serveur.
    • Enfin, dans notre PetsList composant, nous passons le pets accessoires, avec data.pets comme valeur d'objet.

À ce stade, nous avons interrogé avec succès notre serveur.

Pour démarrer notre application, exécutons la commande suivante:

  • Démarrez l'application cliente. Exécutez la commande npm run app dans votre CLI.
  • Démarrez le serveur. Exécutez la commande npm run server dans une autre CLI.
VScode CLI partitionné pour démarrer à la fois le client et le serveur.
VScode CLI partitionné pour démarrer à la fois le client et le serveur. (Grand aperçu)

Si tout s'est bien passé, vous devriez voir ceci:

Animaux interrogés du serveur.
Animaux interrogés du serveur.

Mutation des données

La mutation des données ou la création de données dans Apollo Client est presque identique à l'interrogation de données, avec de très légères modifications.

Toujours dedans client/src/pages/Pets.js, copions et collons le code en surbrillance:

....

const GET_PETS = gql`
  query getPets {
    pets {
      id
      name
      type
      img
    }
  }
`;

const NEW_PETS = gql`
  mutation CreateAPet($newPet: NewPetInput!) {
    addPet(input: $newPet) {
      id
      name
      type
      img
    }
  }
`;

  const Pets = () => {
  const (modal, setModal) = useState(false)
  const { loading, error, data } = useQuery(GET_PETS);
  const (createPet, newPet) = useMutation(NEW_PETS);
  const onSubmit = input => {
    setModal(false)
    createPet({
      variables: { newPet: input }
    });
  }

  if (loading || newPet.loading) return ;
  
  if (error || newPet.error) return 

An error occured

;
if (modal) { return setModal(false)} /> } return (

Pets

) } export default Pets

Pour créer une mutation, nous prendrions les étapes suivantes.

1. mutation

Pour créer, mettre à jour ou supprimer, nous devons effectuer la mutation opération. le mutation l'opération a un CreateAPet nom, avec un argument. Cet argument a un $newPet variable, avec un type de NewPetInput. le ! signifie que l'opération est requise; ainsi, GraphQL n'exécutera l'opération que si nous passons un newPet variable dont le type est NewPetInput.

2. addPet

le addPet fonction, qui est à l'intérieur du mutation opération, prend un argument de input et est réglé sur notre $newPet variable. Les jeux de champs spécifiés dans notre addPet La fonction doit être égale aux ensembles de champs de notre requête. Les jeux de champs dans notre opération sont:

3. useMutation

le useMutation React hook est l'API principale pour exécuter des mutations dans une application Apollo. Lorsque nous avons besoin de muter des données, nous appelons useMutation dans un composant React et passez-lui une chaîne GraphQL (dans notre cas, NEW_PETS).

Lorsque notre composant rend useMutation, il renvoie un tuple (c'est-à-dire un ensemble ordonné de données constituant un enregistrement) dans un tableau qui comprend:

  • une mutate fonction que nous pouvons appeler à tout moment pour exécuter la mutation;
  • un objet avec des champs qui représentent l'état actuel de l'exécution de la mutation.

le useMutation hook reçoit une chaîne de mutation GraphQL (qui est NEW_PETS dans notre cas). Nous avons déstructuré le tuple, qui est la fonction (createPet) qui muteront les données et le champ objet (newPets).

4. createPet

Dans notre onSubmit fonction, peu de temps après la setModal état, nous avons défini notre createPet. Cette fonction prend un variable avec une propriété d'objet d'une valeur définie sur { newPet: input }. le input représente les différents champs de saisie de notre formulaire (comme le nom, le type, etc.).

Une fois cela fait, le résultat devrait ressembler à ceci:

Mutation sans mise à jour instantanée
Mutation sans mise à jour instantanée.

Si vous observez attentivement le GIF, vous remarquerez que notre animal de compagnie créé ne s'affiche pas instantanément, uniquement lorsque la page est actualisée. Cependant, il a été mis à jour sur le serveur.

La grande question est la suivante: pourquoi notre animal ne se met-il pas à jour instantanément? Découvrons-le dans la section suivante.

Mise en cache dans le client Apollo

La raison pour laquelle notre application ne se met pas à jour automatiquement est que nos données nouvellement créées ne correspondent pas aux données du cache dans Apollo Client. Il y a donc un conflit quant à ce qu'il faut exactement mettre à jour à partir du cache.

En termes simples, si nous effectuons une mutation qui met à jour ou supprime plusieurs entrées (un nœud), alors nous sommes responsables de la mise à jour de toutes les requêtes référençant ce nœud, afin qu'il modifie notre mis en cache données pour correspondre aux modifications qu'une mutation apporte à notre back-end Les données.

Garder le cache synchronisé

Il existe plusieurs façons de synchroniser notre cache à chaque fois que nous effectuons une opération de mutation.

La première consiste à récupérer les requêtes correspondantes après une mutation, en utilisant le refetchQueries propriété d'objet (la manière la plus simple).

Remarque: Si nous devions utiliser cette méthode, cela prendrait une propriété d'objet dans notre createPet fonction appelée refetchQueries, et il contiendrait un tableau d'objets avec une valeur de la requête: refetchQueries: ({ query: GET_PETS }).

Étant donné que notre objectif dans cette section n'est pas simplement de mettre à jour nos animaux de compagnie créés dans l'interface utilisateur, mais de manipuler le cache, nous n'utiliserons pas cette méthode.

La deuxième approche consiste à utiliser le update fonction. Dans Apollo Client, il y a un update fonction d'assistance qui aide à modifier les données du cache, afin qu'elles se synchronisent avec les modifications qu'une mutation apporte à nos données back-end. En utilisant cette fonction, nous pouvons lire et écrire dans le cache.

Mise à jour du cache

Copiez le code en surbrillance suivant et collez-le dans client/src/pages/Pets.js:

......
const Pets = () => {
  const (modal, setModal) = useState(false)
  const { loading, error, data } = useQuery(GET_PETS);
  const (createPet, newPet) = useMutation(NEW_PETS, {
    update(cache, { data: { addPet } }) {
      const data = cache.readQuery({ query: GET_PETS });
      cache.writeQuery({
        query: GET_PETS,
        data: { pets: (addPet, ...data.pets) },
      });
    },
    }
  );
  .....

le update La fonction reçoit deux arguments:

  • Le premier argument est le cache d'Apollo Client.
  • La seconde est la réponse de mutation exacte du serveur. Nous déstructurons le data propriété et définissez-le sur notre mutation (addPet).

Ensuite, pour mettre à jour la fonction, nous devons vérifier quelle requête doit être mise à jour (dans notre cas, le GET_PETS query) et lisez le cache.

Deuxièmement, nous devons écrire au query qui a été lu, afin qu'il sache que nous sommes sur le point de le mettre à jour. Nous le faisons en passant un objet qui contient un query propriété object, avec la valeur définie sur notre query opération (GET_PETS) et un data propriété dont la valeur est un pet objet et qui a un tableau des addPet mutation et une copie des données de l'animal.

Si vous avez suivi attentivement ces étapes, vous devriez voir vos animaux se mettre à jour automatiquement au fur et à mesure que vous les créez. Jetons un coup d'œil aux changements:

Les animaux se mettent à jour instantanément
Les animaux domestiques se mettent à jour instantanément.

Interface utilisateur optimiste

Beaucoup de gens sont de grands fans de chargeuses et de fileuses. Il n'y a rien de mal à utiliser un chargeur; il existe des cas d'utilisation parfaits où un chargeur est la meilleure option. J'ai écrit sur les chargeurs par rapport aux spinners et leurs meilleurs cas d'utilisation.

Les chargeurs et les spinners jouent en effet un rôle important dans la conception de l'interface utilisateur et de l'UX, mais l'arrivée d'Optimistic UI a volé la vedette.

Qu'est-ce que l'interface utilisateur optimiste?

L'interface utilisateur optimiste est une convention qui simule les résultats d'une mutation (données créées) et met à jour l'interface utilisateur avant de recevoir une réponse du serveur. Une fois la réponse reçue du serveur, le résultat optimiste est rejeté et remplacé par le résultat réel.

Au final, une interface utilisateur optimiste n'est rien de plus qu'un moyen de gérer les performances perçues et d'éviter les états de chargement.

Apollo Client a une manière très intéressante d'intégrer l'interface utilisateur optimiste. Cela nous donne un crochet simple qui nous permet d'écrire dans le cache local après la mutation. Voyons voir comment ça fonctionne!

Étape 1

Dirigez-vous vers client/src/client.jset ajoutez uniquement le code en surbrillance.

import { ApolloClient } from 'apollo-client'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { HttpLink } from 'apollo-link-http'
import { setContext } from 'apollo-link-context'
import { ApolloLink } from 'apollo-link'
const http = new HttpLink({ uri: "http://localhost:4000/" });
const delay = setContext(
  request => 
    new Promise((success, fail) => {
      setTimeout(() => {
        success()
      }, 800)
    })
)
const link = ApolloLink.from((
  delay,
  http
))
const cache = new InMemoryCache()
const client = new ApolloClient({
  link,
  cache
})
export default client

La première étape comprend les éléments suivants:

  • Nous importons setContext de apollo-link-context. le setContext fonction prend une fonction de rappel et renvoie une promesse dont setTimeout est réglé sur 800ms, afin de créer un délai lorsqu'une opération de mutation est effectuée.
  • le ApolloLink.from garantit que l'activité réseau qui représente le lien (notre API) depuis HTTP est retardé.

Étape 2

L'étape suivante consiste à utiliser le hook Optimistic UI. Revenir à client/src/pages/Pets.jset ajoutez uniquement le code en surbrillance ci-dessous.

.....

const Pets = () => {
  const (modal, setModal) = useState(false)
  const { loading, error, data } = useQuery(GET_PETS);
  const (createPet, newPet) = useMutation(NEW_PETS, {
    update(cache, { data: { addPet } }) {
      const data = cache.readQuery({ query: GET_PETS });
      cache.writeQuery({
        query: GET_PETS,
        data: { pets: (addPet, ...data.pets) },
      });
    },
    }
  );
  const onSubmit = input => {
    setModal(false)
    createPet({
      variables: { newPet: input },
      optimisticResponse: {
        __typename: 'Mutation',
        addPet: {
          __typename: 'Pet',
          id: Math.floor(Math.random() * 10000 + ''),
          name: input.name,
          type: input.type,
          img: 'https://via.placeholder.com/200'
        }
      }
    });
  }
  .....

le optimisticResponse object est utilisé si nous voulons que l'interface utilisateur se mette à jour immédiatement lorsque nous créons un animal de compagnie, au lieu d'attendre la réponse du serveur.

Les extraits de code ci-dessus incluent les éléments suivants:

  • __typename est injecté par Apollo dans la requête pour récupérer le type des entités interrogées. Ces types sont utilisés par Apollo Client pour construire le id propriété (qui est un symbole) à des fins de mise en cache dans apollo-cache. Alors, __typename est une propriété valide de la réponse à la requête.
  • La mutation est définie comme __typename de optimisticResponse.
  • Tout comme précédemment défini, le nom de notre mutation est addPet, et le __typename est Pet.
  • Viennent ensuite les champs de notre mutation que nous voulons que la réponse optimiste mette à jour:
    • id
      Comme nous ne savons pas quel sera l'identifiant du serveur, nous en avons créé un en utilisant Math.floor.
    • name
      Cette valeur est définie sur input.name.
    • type
      La valeur du type est input.type.
    • img
      Maintenant, parce que notre serveur génère des images pour nous, nous avons utilisé un espace réservé pour imiter notre image du serveur.

Ce fut en effet un long trajet. Si vous arrivez à la fin, n’hésitez pas à faire une pause de votre chaise avec votre tasse de café.

Jetons un œil à nos résultats. Le référentiel de prise en charge de ce projet se trouve sur GitHub. Clonez et expérimentez avec.

Résultat final de l'application animalerie
Résultat final de notre application.

Conclusion

Les fonctionnalités étonnantes d'Apollo Client, telles que l'interface utilisateur optimiste et la pagination, font de la création d'applications côté client une réalité.

Alors qu'Apollo Client fonctionne très bien avec d'autres frameworks, tels que Vue.js et Angular, les développeurs React ont Apollo Client Hooks, et ils ne peuvent donc s'empêcher de profiter de la création d'une excellente application.

Dans cet article, nous n'avons fait qu'effleurer la surface. La maîtrise d'Apollo Client exige une pratique constante. Alors, allez-y et clonez le référentiel, ajoutez la pagination et jouez avec les autres fonctionnalités qu'il offre.

Veuillez partager vos commentaires et votre expérience dans la section commentaires ci-dessous. Nous pouvons également discuter de vos progrès sur Twitter. À votre santé!

Références

Éditorial fracassant(ks, ra, al, yk, il)

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *