Comment créer une application de chat avec React et Graphcool

De Get Docs
Aller à :navigation, rechercher

Introduction

GraphQL et React fonctionnent bien ensemble pour fournir aux développeurs des outils permettant de rationaliser les tâches de programmation Web courantes, y compris les intégrations en temps réel. Dans cet article, vous utiliserez React et GraphQL pour créer une application de chat en temps réel.

GraphQL est une spécification de requête construite autour de l'algorithme Graph développé par Facebook. Plutôt que de simplement envoyer des charges utiles JSON via REST à un serveur avec le serveur interrogeant ensuite une base de données, GraphQL sert ces requêtes directement depuis le client. De cette façon, vous vous retrouvez avec exactement ce dont le client a besoin et non ce que le point de terminaison REST expose. Vous utiliserez le Apollo—un client GraphQL—pour interagir avec votre serveur GraphQL depuis votre interface React.

Le processus de configuration d'un serveur et les outils impliqués peuvent également devenir accablants. Parfois, vous pouvez même vous tromper, exposant ainsi vos produits à des failles de sécurité. Graphcool est un serveur GraphQL hébergé très complet avec lequel vous pouvez travailler. Vous pouvez manipuler n'importe quoi sur le serveur en utilisant ses fonctions sans serveur.

Buts

Dans ce didacticiel, vous allez :

  • Mettre en place un projet React et GraphQL
  • Utilisez Apollo pour interagir avec un serveur GraphQL de React
  • Interroger et faire muter des entités
  • Mettre en œuvre la messagerie et les abonnements en temps réel

Conditions préalables

Pour terminer ce tutoriel, vous aurez besoin de :

Ce didacticiel suppose une connaissance de JavaScript et une certaine familiarité avec React et GraphQL.

Étape 1 - Configuration d'un projet React

create-react-app a été l'outil préféré des développeurs pour échafauder les applications React. Échafaudez un nouveau projet dans React en exécutant la commande suivante :

npx create-react-app graphql-chat

Cela créera un nouveau dossier nommé graphql-chat et téléchargez tous les fichiers React nécessaires avec lesquels vous devez travailler.

Mettre à jour les dépendances dans le package.json comme suit:

package.json

"dependencies": {
  "apollo-client-preset": "^1.0.6",
  "apollo-link-ws": "^1.0.4",
  "graphql": "^0.12.3",
  "graphql-tag": "^2.6.1",
  "react": "^16.2.0",
  "react-apollo": "^2.0.4",
  "react-dom": "^16.2.0",
  "react-scripts": "1.0.17",
  "subscriptions-transport-ws": "^0.9.4"
},

Exécutez ensuite la commande install pour télécharger tous ces fichiers :

npm install

Nous apprendrons ce que fait chacune de ces dépendances lorsque nous les rencontrons.

Certains fichiers CSS globaux doivent être inclus afin de soulager les problèmes de style de notre part pour ce projet. Mettre à jour le head faire public/index.html pour inclure les fichiers CSS suivants :

public/index.html

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/7.0.0/normalize.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/skeleton/2.0.4/skeleton.min.css" />

Ce sont des références aux fichiers hébergés par CDN pour Normalize et Skeleton. Normaliser nous permet d'avoir une ligne de base cohérente entre les différents styles de navigateur par défaut. Skeleton nous fournit des outils de mise en page et de typographie.

Étape 2 - Configuration d'une instance GraphQL

Plutôt que d'avoir un serveur local en cours d'exécution, nous pouvons utiliser un service hébergé gratuit existant pour configurer une instance GraphQL. Ce n'est pas seulement gratuit, mais moins de tâches et plus facile à démarrer. Graphcool est utile pour les projets petits, grands et croissants.

Pour configurer une instance, vous devez d'abord installer l'outil CLI Graphcool. Cet outil expose des commandes pour créer de nouveaux serveurs GraphQL, les mettre à jour et les déployer. Il peut également être utilisé pour gérer les fonctions cloud de Graphcool. Exécutez la commande suivante pour installer :

npm install -g graphcool-framework

Accédez à l'application React que nous venons de configurer via le terminal et démarrez un nouveau serveur Graphool :

graphcool-framework init server

Cette commande créera un dossier dans le projet React nommé server. La server La commande contient des définitions de type et de schéma pour vos données GraphQL. Vous pouvez consulter Comprendre les requêtes d'API GraphQL ainsi que les articles dans ce résultat de recherche pour en savoir plus sur les fondamentaux de GraphQL.

Pour notre application de chat, nous devons juste nous concentrer sur le types.graphql fichier généré dans le dossier du serveur. C'est ici que vous dites à GraphQL à quoi ressemble la structure de vos données. C'est ce qu'on appelle une définition de type. Remplacez son contenu par ce qui suit :

serveur/types.graphql

type Chat @model {
  id: ID! @isUnique
  from: String!
  content: String!
  createdAt: DateTime!
}

Vous devez déployer ce schéma sur le serveur Graphcool :

graphcool-framework deploy

Cela ouvrira d'abord un navigateur pour vous permettre de configurer un compte Graphcool, puis de déployer votre instance. Vous pouvez ouvrir l'instance à partir du menu en haut à gauche de votre tableau de bord Graphcool.

De retour dans le terminal, le processus imprimera une URL importante dont vous avez besoin pour interagir avec votre serveur Graphcool. Stockez cette URL où vous pouvez vous y référer.

Une fois l'application déployée, ouvrez le terrain de jeu pour tester si le processus de déploiement a mis en place toutes vos définitions de type :

graphcool-framework playground

Exécutez la requête et la mutation suivantes dans l'éditeur de gauche et cliquez sur le bouton Exécuter pour les exécuter :

query FETCH_CHATS{
  allChats{
    from,
    content
  }
}

mutation CREATE_CHAT {
  createChat(content: "test", from: "test") {
    content,
    from
  }
}

Le terrain de jeu vous demandera laquelle des commandes vous souhaitez exécuter.

Étape 3 - Fournir l'instance GraphQL pour réagir

Un projet React est prêt et un serveur GraphQL est cuit. Et ensuite ? Nous devons les lier avec tous ces modules que nous avons installés avec le package.json dossier.

Commençons par les importer. Mettre à jour le src/index.js fichier d'entrée pour importer les dépendances suivantes :

src/index.js

import { ApolloProvider } from 'react-apollo';
import { ApolloClient } from 'apollo-client';
import { HttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { ApolloLink, split } from 'apollo-client-preset'
import { WebSocketLink } from 'apollo-link-ws'
import { getMainDefinition } from 'apollo-utilities'

Juste sous les importations, configurez le lien WebSocket. Vous pouvez le faire en utilisant le WebSocketLink module:

src/index.js

// ...

const wsLink = new WebSocketLink({
  uri: '[Subscriptions API URI]',
  options: {
    reconnect: true
  }
})

La fonction constructeur prend un objet avec des options de configuration. La uri est nécessaire et doit être le même que le Subscriptions API URI que vous avez reçu après le déploiement. Nous utiliserons l'option de reconnexion pour demander à WebSocket d'essayer de se reconnecter après une tentative infructueuse.

Nous ne faisons pas qu'établir une connexion WebSocket. Nous devons également configurer une connexion HTTP pour les opérations de requête-réponse. Ajoutez ceci juste en dessous de la configuration du lien WebSocket :

src/index.js

// ...

const httpLink = new HttpLink({ uri: '[SIMPLE API URI]' })

Le même que WebSocketLink constructeur mais utilise l'URI de l'API simple. Nous n'avons besoin de passer aucune option de configuration.

À ce stade, nous avons deux liens. Nous utiliserons le split méthode pour indiquer au serveur quand utiliser quel lien :

src/index.js

// ...

const link = split(
  ({ query }) => {
    const { kind, operation } = getMainDefinition(query)
    return kind === 'OperationDefinition' && operation === 'subscription'
  },
  wsLink,
  httpLink,
)

La split La méthode prend trois arguments. Le premier est un test qui renvoie un booléen. Si la valeur booléenne est true, la requête est transmise au second (wsLink) dispute. Si false, il est transmis au troisième (httpLink) dispute.

Maintenant, nous pouvons créer un client Apollo avec le lien renvoyé :

src/index.js

// ...

const client = new ApolloClient({
  link,
  cache: new InMemoryCache()
})

Vous pouvez faire des demandes directement à votre serveur en utilisant les URL fournies. C'est un peu plus difficile que d'utiliser une bibliothèque wrapper qui fournit des fonctionnalités pour simplifier l'interaction avec le serveur. Apollo est l'une de ces bibliothèques.

Fournir au client en utilisant le AppProvider composant:

src/index.js

// ...

ReactDOM.render(
  <ApolloProvider client={client}>
    <App />
  </ApolloProvider>,
  document.getElementById('root')
);

Étape 4 - Interroger le serveur GraphQL

Avec le lien entre notre application React et notre ensemble GraphQL, il est temps de commencer à interroger la base de données et à afficher les données dans le navigateur.

Mettre à jour le src/App.js pour configurer une requête :

src/App.js

import React, { Component } from 'react';

// Import GraphQL helpers
import { graphql } from 'react-apollo';
import gql from 'graphql-tag';

// App component styles
import './App.css';

class App extends Component {
  state = {
    from: 'anonymous',
    content: ''
  };
  componentDidMount() {
    // Get username from prompt when page loads
    const from = window.prompt('username');
    from && this.setState({ from });
  }
  render() {
    // Coming up next
  }
}

const ALL_CHATS_QUERY = gql`
  query AllChatsQuery {
    allChats {
      id
      createdAt
      from
      content
    }
  }
`;

export default graphql(ALL_CHATS_QUERY, { name: 'allChatsQuery' })(App);

Décomposons ce qui se passe ici :

  • Nous importons d'abord graphql et gql. Ces bibliothèques aideront respectivement à configurer et à analyser la requête.
  • A la fin de la définition de la classe du composant, nous créons la requête. Cela ressemble exactement à ce que nous avons fait dans la cour de récréation mais enveloppé avec le gql méthode utilisant le balisage de modèle.
  • La graphql HOC (Higher-Order Component) est ensuite utilisé pour exposer le résultat de cette requête aux props du composant App.

Vous pouvez maintenant afficher la requête dans le DOM (Document Object Model) via les accessoires :

src/App.js

// ...

// Chatbox UI component
import Chatbox from './components/Chatbox';

// ...

class App extends Component {

  // ...

  render() {
    const allChats = this.props.allChatsQuery.allChats || [];
    return (
      <div className="">
        <div className="container">
          <h2>Chats</h2>
          {allChats.map(message => (
            <Chatbox key={message.id} message={message} />
          ))}
        </div>
      </div>
    );
  }
}

// ...

La méthode de rendu itère sur chacun des résultats de la requête et les imprime à l'écran à l'aide de la propriété Chatbox composant. Voici à quoi ressemble le composant dans components/Chatbox.js:

src/components/Chatbox.js

import React from 'react';
import './Chatbox.css'

const Chatbox = ({message}) => (
  <div className="chat-box">
    <div className="chat-message">
      <h5>{message.from}</h5>
      <p>
        {message.content}
      </p>
    </div>
  </div>
);

export default Chatbox;

Vous pouvez vous référer au référentiel pour obtenir les styles de base pour Chatbox.css et App.css.

Étape 5 - Création de nouveaux messages

Les mutations dans GraphQL sont utilisées pour créer, modifier et supprimer des valeurs de votre base de données. Là où une requête est le R (Read) dans CRUD, une mutation peut être le C, U, D (Create, Update , Effacer). Nous sommes déjà en mesure de lire les messages existants dans notre application de chat. La prochaine chose dont nous devrions nous soucier est de créer ces messages à partir de notre application React.

Tout comme nous avons créé une requête, nous pouvons également créer une mutation :

src/App.js

// ...

// Import GraphQL helpers
import { graphql, compose } from 'react-apollo';

// ...

class App extends Component {

  // ...

}

// ...

const CREATE_CHAT_MUTATION = gql`
  mutation CreateChatMutation($content: String!, $from: String!) {
    createChat(content: $content, from: $from) {
      id
      createdAt
      from
      content
    }
  }
`;

export default compose(
  graphql(ALL_CHATS_QUERY, { name: 'allChatsQuery' }),
  graphql(CREATE_CHAT_MUTATION, { name: 'createChatMutation' })
)(App);

La mutation ressemble beaucoup à une requête mais reçoit des paramètres—content et from. Nous devons envelopper le App composant avec à la fois cette mutation et notre requête existante. Pour cette raison, nous importons également les compose méthode et utilisez cette méthode pour envelopper les deux HOC.

Dans la méthode de rendu, nous pouvons avoir un élément d'entrée qui collecte ces contenus de message :

src/App.js

// ...

class App extends Component {

  // ...

  render() {
    const allChats = this.props.allChatsQuery.allChats || [];
    return (
        <div className="">
          <div className="container">
            <h2>Chats</h2>
            {allChats.map(message => (
              <Chatbox key={message.id} message={message} />
            ))}
            {/* Message content input */}
            <input
              value={this.state.content}
              onChange={e => this.setState({ content: e.target.value })}
              type="text"
              placeholder="Start typing"
              onKeyPress={this._createChat}
            />
          </div>
        </div>
      );
    }
  }
}

// ...

L'entrée déclenche un événement à chaque keyPress, et cet événement appelle le _createChat méthode. Voici la définition de cette méthode dans le App classer:

src/App.js

// ...

class App extends Component {
  // ...

  _createChat = async e => {
    if (e.key === 'Enter') {
      const { content, from } = this.state;
      await this.props.createChatMutation({
        variables: { content, from }
      });
      this.setState({ content: '' });
    }
  };

  // ...
}

// ...

Nous ne voulons exécuter la mutation que lorsque la touche Entrée est enfoncée. Remarquez comment le createChatMutation est également exposé sur props, et la variable est transmise en tant qu'objet à la méthode de mutation.

Lorsque vous envoyez un nouveau message, rien ne se passe jusqu'à ce que vous rechargez. Cela nécessite des mises à jour en temps réel.

Étape 6 - Configuration des abonnements en temps réel

Les abonnements dans GraphQL sont utilisés pour écouter les modifications apportées par les clients connectés. Ces clients peuvent agir sur ces changements en conséquence. Probablement en mettant à jour l'interface utilisateur avec les données modifiées ou même en envoyant des notifications push. La technologie sous-jacente qui alimente les abonnements est les WebSockets bien connus.

Ajoutez cette méthode à la App class pour configurer un abonnement :

src/App.js

// ...

class App extends Component {
  // ...

  _subscribeToNewChats = () => {
    this.props.allChatsQuery.subscribeToMore({
      document: gql`
        subscription {
          Chat(filter: { mutation_in: [CREATED] }) {
            node {
              id
              from
              content
              createdAt
            }
          }
        }
      `,
      updateQuery: (previous, { subscriptionData }) => {
        const newChatLinks = [
          ...previous.allChats,
          subscriptionData.data.Chat.node
        ];
        const result = {
          ...previous,
          allChats: newChatLinks
        };
        return result;
      }
    });
  };

  // ...
}

// ...

La allChatsQuery expose un subscribeToMore méthode. Une fois que cette méthode est appelée, elle ouvre un canal de communication en temps réel. La méthode prend un objet dont on peut définir le document de requête et un updateQuery méthode.

Le document définit un abonnement et écoute lorsqu'une mutation se produit sur le Chat entité avant de déclencher un événement. La méthode de mise à jour reçoit l'ancienne et la nouvelle valeur, et nous utilisons ces nouvelles valeurs pour mettre à jour l'ancienne valeur.

Vous pouvez lancer cet abonnement dans le componentDidMount méthode du cycle de vie :

src/App.js

// ...

class App extends Component {
  // ...

  componentDidMount() {
    const from = window.prompt('username');
    from && this.setState({ from });
    this._subscribeToNewChats();
  }

  // ...
}

// ...

Une fois que vous exécutez à nouveau, vous aurez une application de chat qui fonctionne.

npm start

Vous avez maintenant créé une application de chat en utilisant React et Graphcool.

Conclusion

Dans ce didacticiel, vous avez créé une application de chat en temps réel avec React et GraphQL. Pour plus de contenu et de didacticiels React, vous pouvez visiter notre page React Topic.