Créer une fenêtre de chat en utilisant React et des crochets
Published: 2024-03-07 07:50:07

**Avant de poursuivre**...Cet article tiré de nos archives utilise notre PubNub React SDK mais les nouvelles applications de Chat devraient utiliser notre [Chat SDK](https://www.pubnub.com/docs/chat/chat-sdk/overview) dédié, écrit en TypeScript et l'[application d'exemple](https://www.pubnub.com/docs/chat/chat-sdk/build/sample-chat) qui l'accompagne, qui utilise des crochets.

Le[chat](https://pubnub.com/solutions/chat/) est un élément clé de la plupart des applications interactives. Qu'il s'agisse d'[une application de santé](https://pubnub.com/solutions/digital-health/), de [chats de groupe](https://www.pubnub.com/solutions/multiuser-collaboration/) ou de chatbots, la communication en temps réel est une attente de toute application multi-utilisateurs. L'intégration de cette fonctionnalité est beaucoup plus transparente si vous choisissez le bon framework et la bonne infrastructure dès le départ. Dans ce tutoriel, nous allons vous montrer comment le faire - en créant une fenêtre de chat à l'aide de [React](https://reactjs.org/), [Material-UI](https://material-ui.com/) et [PubNub](https://www.pubnub.com/).

Notre application permettra à quiconque de se connecter et de discuter en temps réel sur le canal de son choix. Nous allons créer ce chat à partir de zéro en utilisant le framework React et les composants Material-UI. L'API PubNub est utilisée pour gérer l'envoi et la réception des messages. Ces trois éléments nous aideront à créer un chat moderne et rapide.

Dans ce tutoriel, nous utilisons également les [Hooks](https://reactjs.org/docs/hooks-intro.html), une nouvelle façon d'écrire des composants React qui réduit le code redondant et organise les éléments connexes. J'expliquerai plus en détail pourquoi et comment nous utilisons ces nouvelles fonctionnalités plus tard dans le tutoriel. Après ce tutoriel, nous aurons un chat qui permettra à toute personne ayant un nom de canal de se parler. Les canaux sont représentés dans l'URL et sur la page, de sorte qu'il est facile de les partager !

[![react hooks chat](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1jkx/cadaa09d1dbce7a6f13e1fce08cc4a30/react-hooks-chat.gif)](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1jkx/cadaa09d1dbce7a6f13e1fce08cc4a30/react-hooks-chat.gif)

Pub/Sub et récupération de l'historique
---------------------------------------

PubNub fournit une infrastructure simple et extrêmement rapide pour l'envoi de messages. PubNub est utilisé pour connecter des quantités virtuellement illimitées de personnes ou de systèmes, en moins d'un quart de seconde, voire moins, dans le monde entier. Il couvre tous les cas d'utilisation grâce à ses nombreux SDK disponibles et à son[centre de ressources axé sur le chat](https://www.pubnub.com/developers/chat-resource-center/). Dans la création de cette application, nous utiliserons Publish/Subscribe pour la messagerie en temps réel et Storage & Playback pour conserver les messages.

La**publication** nous fournit un moyen d'envoyer des messages à ceux qui écoutent sur des canaux spécifiques. Apprenez à [publier dans React](https://www.pubnub.com/docs/sdks/react#publish-and-subscribe).

**S'abonner** est le moyen de dire à PubNub que nous voulons recevoir des messages envoyés à des canaux spécifiques. Apprenez àvous [abonner avec Re](https://www.pubnub.com/docs/sdks/react#publish-and-subscribe)act.

**Storage & Playback** signifie que quelqu'un n'a pas besoin d'être abonné au moment même pour recevoir des messages sur un canal. Lorsqu'un utilisateur se connecte, nous pouvons récupérer les derniers messages pour qu'il puisse les consulter ! Apprenez comment [stocker et lire des messages dans React.](https://www.pubnub.com/docs/react-native-javascript/api-reference-storage-and-playback)

Pour commencer
--------------

Dans cet exemple de chat, nous n'avons besoin d'utiliser qu'une seule API pour toutes les fonctionnalités du chat. Vous devez créer un compte PubNub en utilisant le formulaire ci-dessous, ou vous connecter si vous avez déjà un compte.

Toutd'abord, obtenez vos clés pub/sub uniques dans le [tableau de bord de l'administrateur,](https://admin.pubnub.com/) puis activez le stockage et la lecture en bas à gauche de votre page d'options de clés. J'ai fixé la durée de conservation de mes messages à un jour, mais vous pouvez choisir la durée qui vous convient le mieux. Veillez à enregistrer vos modifications.

Maintenant que tout est en place, nous pouvons commencer à configurer notre projet React.

### Comment installer React.js et PubNub

Afin d'installer React.js et PubNub, nous devons d'abord nous assurer que nous avons Node.js et npm. Installez-les sur la [page d'accueil officielle de Node.js](https://nodejs.org/en/). Si vous les avez déjà installés, assurez-vous que votre version de npm est supérieure à 5.2 en entrant

```js
npm -v
```

dans votre terminal. Nous avons maintenant nos gestionnaires de paquets pour créer notre application React et installer notre SDK PubNub.

Une fois que vous avez installé Node.js, exécutez ces commandes pour créer votre projet et installer les modules nécessaires. Attendez que React construise votre site web ! Une fois que c'est fait, la deuxième ligne installera PubNub. La troisième ligne installera notre framework de style Material-UI.

```js
npx create-react-app <your-app-name>
cd <your-app-name>
npm install --save pubnub
npm install @material-ui/core
```

Nous avons maintenant tout ce qu'il faut pour commencer à coder ! Si vous entrez

```js
npm start
```

dans votre terminal et que vous cliquez sur le lien qu'il fournit une fois qu'il est lancé, vous devriez voir une page react vide ! Commençons à coder !

Pourquoi utiliser React Hooks ?
-------------------------------

Avant octobre 2018, vous deviez utiliser des [composants de classe pour stocker des variables locales](https://reactjs.org/docs/state-and-lifecycle.html#adding-local-state-to-a-class). Les Hooks nous ont apporté la possibilité de sauvegarder l'état à l'intérieur des composants fonctionnels et les Hooks ont supprimé une grande partie du gonflement qui vient avec les classes.

Les crochets facilitent le développement d'applications à grande échelle, ses fonctions nous aident à regrouper le code similaire. Nous organisons la logique de nos composants en fonction de ce qu'ils font et non du moment où ils doivent le faire. Nous renonçons aux fonctions habituelles du cycle de vie telles que componentDidMountetcomponentDidUpdate et utilisons plutôt useEffect.

useEffect est l'un des deux principaux hooks que nous utilisons, l'autre étant useState. useState est le nouveau setState mais fonctionne un peu différemment. La [documentation de React Hooks](https://reactjs.org/docs/hooks-intro.html) entre dans le détail de quelques autres, mais une autre partie intéressante des Hooks est que nous pouvons créer les nôtres ! Cela permet d'économiser du temps et des lignes de code en utilisant ce que nous avons déjà fait.

Dans ce tutoriel, je vais vous montrer comment utiliser useEffect, useState, et créer votre propre hook !

Créer un hook React personnalisé
--------------------------------

Commençons par créer notre propre hook qui nous simplifiera le code à l'avenir. Au lieu de créer des fonctions onChange individuellement pour chaque entrée, nous allons regrouper ce que nous pouvons pour chacun d'entre eux maintenant, dans un seul Hook !

Si vous regardez dans le dossier de votre projet que nous avons créé, vous pouvez voir que nous avons quelques dossiers différents. Naviguez dans le dossier "src" et créez un nouveau fichier appelé "useInput.js". Les règles relatives aux crochets stipulent que tous les crochets doivent commencer par "use". Elles précisent également que les crochets ne doivent être utilisés qu'au niveau supérieur, c'est-à-dire que nous ne pouvons pas les utiliser dans des fonctions, des conditions ou des boucles. Nous ne pouvons pas non plus les appeler à partir de fonctions JS ordinaires, mais uniquement à partir de composants de fonctions React et de Hooks personnalisés ! Maintenant que nous connaissons les règles générales derrière eux, créons-en un !

À travers ce crochet, nous utiliserons le crochet useState. Importez useState depuis 'react' en haut de votre fichier et après avoir créé une fonction nommée, vous l'avez deviné, 'useInput'.

```js
import { useState } from 'react';
function useInput()
{
  //Define our Hook
}
```

C'est ici que nous pouvons nous amuser un peu avec notre syntaxe. Nous pouvons utiliser une affectation de déstructuration pour recevoir les deux objets que useState nous donne, en utilisant seulement une ligne de code. Mais que nous donne useState ? En fait, il nous renvoie un getter et un setter, une variable qui contient la valeur et une fonction pour la définir ! Au lieu d'accéder à notre état par

```js
this.state.xxxxx
```

nous pouvons y accéder uniquement par son nom.

```js
let [value, setValue] = useState('');
```

Créez une expression de fonction assignée à une nouvelle variable que nous avons créée et qui s'appelle onChange. Nous passons "event" à travers la fonction et à l'intérieur, nous fixons la valeur de notre état à la valeur de la cible de l'événement. Ensuite, renvoyons les trois variables/fonctions que nous avons créées : value, setValue et onChange.

```js
let onChange = function(event){
  setValue(event.target.value);
};
return {
  value,
  setValue,
  onChange
};
```

Enfin

```js
export default useInput;
```

à la fin de notre fichier pour le rendre disponible pour notre application principale !

Conception de nos composants React
----------------------------------

Maintenant que notre Hook est terminé. Mettons en place notre fichier App.js ! Nous avons quelques fichiers clés à importer au début de notre fichier : React et les deux Hooks par défaut dont nous avons besoin, notre hook useInput que nous venons de créer, notre fichier App.css, PubNub, et les composants Material-UI.

Remplacez ce qui se trouve dans votre App.css par ce qui suit.

```js
* {
  margin: 0;
  padding: 0;
}
body {
  width: 500px;
  margin: 30px auto;
  background-color: #fff;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
    "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
    sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
code {
  font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
    monospace;
}
.top {
    display: flex;
    flex-direction: row;
    justify-content: space-between;
}
```

Faisons une ébauche de notre chat en utilisant les en-têtes de nos composants fonctionnels. Cela nous aidera à déterminer le type de design et de flux que nous voulons pour notre chat. J'ai choisi trois composants différents : App, Log et Message.

App contient le journal, les entrées et le bouton de soumission. Log contient une liste de messages, et Message affiche le message et son expéditeur. Veillez à importer les modules requis au début de votre fichier !

```js
//These are the two hooks we use the most of through this Chat
import React, { useState, useEffect} from 'react';
//has a few css stylings that we need.
import './App.css';
//This is a hook we created to reduce some of the bloat we get with watching inputs for changes.
import useInput from './useInput.js';
//Lets us import PubNub for our chat infrastructure capabailites.
import PubNub from 'pubnub';
//Material UI Components
import {Card, CardActions, CardContent,List, ListItem,Button,Typography,Input} from '@material-ui/core';
// Our main Component, the parent to all the others, the one to rule them all.
function App(){
  //Bunch of functions!
  //return()
}
//Log functional component that contains the list of messages
function Log(props){
  //return()
}
//Our message functional component that formats each message.
function Message(props){
  //return()
}
```

Chacun de ces composants comprend une fonction de retour qui nous permet de concevoir ce à quoi il ressemblera. Nous pouvons décider des informations que nous transmettons de nos parents à nos enfants. Grâce à cette conception, nous ne transmettons que des informations vers le bas, en donnant à chaque composant ce dont il a besoin pour fonctionner.

Mise en place de l'App Component : État avec React Hooks
--------------------------------------------------------

Notre App est notre composant principal de chat React. Pour ce composant, il y a quelques choses que nous devons mettre en place, comme la vérification de l'URL pour tout changement du canal, la mise en place de nos états, puis nous pouvons faire quelques fonctions useEffect pour trier ce que nous voulons qu'App fasse, et quand tout cela se produit.

La première action à l'intérieur de notre application est de créer un canal par défaut. "Global" est un bon canal. Ensuite, nous vérifions s'il y a un canal dans l'URL. S'il n'y en a pas, nous pouvons laisser le canal par défaut tel quel, mais s'il y en a un, nous lui attribuons le canal par défaut.

```js
let defaultChannel = "Global";
//Access the parameters provided in the URL
let query = window.location.search.substring(1);
let params = query.split("&");
for(let i = 0; i < params.length;i++){
  var pair = params[i].split("=");
  //If the user input a channel then the default channel is now set
  //If not, we still navigate to the default channel.
  if(pair[0] === "channel" && pair[1] !== ""){
    defaultChannel = pair[1];
  }
}
```

Définissons nos états avec leurs valeurs initiales. Utilisez useState pour obtenir des getters et setters pour notre canal, en vous assurant de mettre notre canal par défaut comme valeur initiale. Faites de même pour notre tableau de messages, mais initialisez-le à un tableau vide.

J'ai également défini un nom d'utilisateur générique pour l'utilisateur, basé sur l'heure actuelle. Ensuite, nous définissons un canal temporaire et une variable de message pour le nouveau crochet que nous avons créé. Et voilà, nous avons mis en place nos états pour notre application.

```js
const [channel,setChannel] = useState(defaultChannel);
const [messages,setMessages] = useState([]);
const [username,] = useState(['user', new Date().getTime()].join('-'));
const tempChannel = useInput();
const tempMessage = useInput();
```

useEffect dans React
--------------------

Ensuite, nous allons utiliser le nouveau useEffect dont tout le monde parle. Cela remplace et réorganise toutes les anciennes méthodes de cycle de vie lorsque nous n'utilisions pas de hooks. Chaque fonction s'exécute à chaque rerendu à moins que nous ne spécifiions un tableau de variables comme second paramètre à suivre. Chaque fois que ces variables changent, la fonction useEffect est réexécutée.

_N'OUBLIEZ PAS : Il s'agit d'un contrôle d'égalité SHALLOW. Les nombres et les chaînes de caractères seront considérés comme différents chaque fois que vous les définirez comme autre chose, mais useEffect ne s'intéresse qu'aux pointeurs des objets, pas à leurs attributs._

Nous pouvons avoir plusieurs de ces fonctions, mais chacun de leurs deuxièmes paramètres doit être différent. Essentiellement, chaque useEffect est groupé par ce dont il dépend pour changer, ainsi les actions avec des dépendances similaires sont exécutées ensemble.

```js
useEffect(()=>{
  //Put code we want to run every time these next variables/states change
},[channel, username]);
```

Configurer PubNub dans React
----------------------------

Maintenant que nous savons comment fonctionne ce nouveau Hook, la prochaine étape est de créer un nouvel objet PubNub ! Ouvrez PubNub pour récupérer les clés de publication et d'abonnement que nous avons générées plus tôt, et placez-les dans votre nouvel objet. Vous pouvez également[définir un UUID](https://www.pubnub.com/docs/react-native-javascript/api-reference-configuration#uuid) pour cette connexion, qu'il s'agisse d'une IP, d'un nom d'utilisateur, d'un [UUID généré](https://www.pubnub.com/docs/react-native-javascript/api-reference-configuration#generate-uuid-arg) ou de tout autre identifiant unique défini dans votre cas d'utilisation. Pour des raisons de simplicité, j'ai choisi le nom d'utilisateur.

```js
const pubnub = new PubNub({
  publishKey: "<ENTER-PUB-KEY-HERE>",
  subscribeKey: "<ENTER-SUB-KEY-HERE>",
  uuid: username
});
```

Après avoir rempli notre objet avec nos informations de connexion, incluons un [Listener pour les événements PubNub](https://www.pubnub.com/docs/web-javascript/api-reference-publish-and-subscribe#listeners)! Ceci est utile pour détecter les nouveaux messages, les nouvelles connexions ou les nouveaux statuts, et pour gérer les événements de présence également. Notre application n'utilise pas la présence et ne nécessite pas non plus la création d'un listener de statut, mais j'aime au moins implémenter le statut et enregistrer certains résultats. Ce dont nous avons vraiment besoin pour notre application est la capacité de recevoir et de gérer les messages entrants, alors définissons cela !

Vérifier si le texte du message est nul ou vide, et si ce n'est pas le cas, créer un objet newMessage. Définir le tableau des messages comme son état actuel concaténé avec le nouveau message que nous recevons. La fonction arrow permet de s'assurer que nous utilisons l'état actuel des messages et non l'état du rendu initial.

```js
pubnub.addListener({
  status: function(statusEvent) {
    if (statusEvent.category === "PNConnectedCategory") {
      console.log("Connected to PubNub!")
    }
  },
  message: function(msg) {
    if(msg.message.text){
      let newMessages = [];
      newMessages.push({
        uuid:msg.message.uuid,
        text: msg.message.text
      });
      setMessages(messages=>messages.concat(newMessages))
    }
  }
});
```

L'abonnement au canal dans notre état sera notre première connexion au serveur PubNub ! Si la présence est importante pour votre cas d'utilisation, c'est ici que vous l'activez. Découvrez qui est dans un canal avec [Presence sur le SDK React de PubNub](https://www.pubnub.com/docs/react-native-javascript/api-reference-presence).

```js
pubnub.subscribe({
  channels: [channel]
});
```

L'incorporation de l'historique est une caractéristique clé de tout chat, alors tirons quelques messages pour former un journal de chat. Lorsque nous nous connectons pour la première fois à un canal, nous utilisons la fonction d'historique pour récupérer les messages stockés. Utilisez la réponse pour accéder aux anciens messages et les stocker dans un tableau temporaire. Puisque notre tableau devrait être vide, nous pouvons pousser ces anciens messages dans notre tableau de messages vide.

```js
pubnub.history({
      channel: channel,
      count: 10, // 100 is the default
      stringifiedTimeToken: true // false is the default
}, function (status, response){
  let newMessages = [];
  for (let i  = 0; i < response.messages.length;i++){
    newMessages.push({
      uuid:response.messages[i].entry.uuid ,
      text: response.messages[i].entry.text
    });
  }
  setMessages(messages=>messages.concat(newMessages))
});
```

Une autre partie géniale de useEffect est que nous pouvons définir un comportement qui arrête tout avant que le programme ne s'exécute à nouveau ! Renvoyons une fonction "cleanup" et à l'intérieur, [désinscrivons nous de tous les canaux](https://pubnub.com/developers/chat-resource-center/docs/reference/connecting#disconnecting-from-pubnub), et plaçons les messages dans un autre tableau vide.

```js
return function cleanup(){
  pubnub.unsubscribeAll();
  setMessages([]);
}
```

Pub/Sub : Publication
---------------------

Nous nous sommes abonnés à un canal, mais nous n'avons pas encore publié. Contrairement aux fonctionnalités PubNub de l'useEffect précédent, nous voulons publier lorsque l'utilisateur envoie un message. Créons une fonction nommée publishMessage qui publiera des messages sur notre canal.

Créez la fonction et vérifiez s'il y a quelque chose dans notre message temporaire. Si c'est le cas, créez votre objet message ! J'ai inclus le message et le nom d'utilisateur pour que nous sachions qui l'a envoyé lorsque nous accédons aux messages depuis n'importe quel appareil. Commencez par créer un autre objet PubNub, exactement le même que le précédent. Appelez publish sur cet objet, en incluant notre nouveau message et notre canal en tant qu'argument.

Après avoir envoyé le message, effacez l'état temporaire du message. Cela permet à l'utilisateur d'en envoyer un autre s'il le souhaite. Nous n'avons pas encore de code appelant cette fonction, donc elle ne sera pas activée, mais la prochaine fonction que nous définirons le sera !

```js
function publishMessage(){
  if (tempMessage.value) {
    let messageObject = {
      text: tempMessage.value,
      uuid: username
    };
    const pubnub = new PubNub({
      publishKey: "<ENTER-PUB-KEY-HERE>",
      subscribeKey: "<ENTER-SUB-KEY-HERE>",
      uuid: username
    });
    pubnub.publish({
      message: messageObject,
      channel: channel
    });
    tempMessage.setValue('');
  }
}
```

Création de gestionnaires d'événements React
--------------------------------------------

Il est important de créer des interactions fluides entre l'utilisateur et notre chat. Créons un gestionnaire pour que les utilisateurs envoient un message ou changent de canal en appuyant sur la touche "Entrée". Nous allons créer une fonction que j'ai appelée handleKeyDown, qui prend un objet événement.

```js
function handleKeyDown(event){
  //Handling key down event
}
```

Une fois à l'intérieur de cette fonction, notre objectif est de déterminer ce qui déclenche cet événement. Plus tard, lorsque nous créerons les entrées, nous leur attribuerons des identifiants. Commençons par vérifier l'identifiant de la cible de l'événement. S'il s'agit de "messageInput", vérifiez à nouveau si la touche pressée était "Entrée" ou non. Si c'est le cas, allez-y et appelez notre fonction publishMessage.

```js
if(event.target.id === "messageInput"){
  if (event.key === 'Enter') {
    publishMessage();
  }
}
```

Effectuez les mêmes vérifications pour démarrer cette instruction else if que la précédente, mais en utilisant cette fois "channelInput" comme identifiant. Créez une valeur constante qui contient notre canal temporaire, mais assurez-vous de couper tout espace blanc de début ou de fin. Si nous n'appelions que setChannel ici, nous n'aurions pas besoin de vérifier si le nouveau et l'ancien canal sont identiques.

Comme nous remplaçons également l'URL actuelle par celle que nous avons créée, nous avons besoin de vérifier qu'il n'y a pas de doublons inutiles. La création d'une nouvelle chaîne d'URL qui inclut le nom du nouveau canal permet également aux utilisateurs de partager plus facilement les liens de la page. Enfin, définissez l'état de notre canal temporaire comme une chaîne vide.

```js
else if(event.target.id === "channelInput"){
  if (event.key === 'Enter') {
    //Navigates to new channels
    const newChannel = tempChannel.value.trim()
    if(newChannel){
      if(channel !== newChannel){
        //If the user isnt trying to navigate to the same channel theyre on
        setChannel(newChannel);
        let newURL = window.location.origin + "?channel=" + newChannel;
        window.history.pushState(null, '',newURL);
        tempChannel.setValue('');
      }
    }
  //What if there was nothing in newChannel?
}
```

C'est parfait si l'utilisateur saisit un canal dans notre entrée, mais qu'en est-il s'il ne le fait pas ? Nous pouvons soit l'alerter de son erreur, soit rester sur le même canal, soit l'emmener sur un canal par défaut de notre choix. J'ai opté pour la dernière option, qui consiste à l'amener à "Global". Nous procédons à la même vérification que précédemment, mais nous utilisons cette fois "Global" et nous définissons le canal comme tel.

Nous créons une nouvelle URL et l'envoyons à l'historique de notre page comme précédemment, mais sans aucun paramètre. Le code que nous avons inclus au début de notre application le reconnaîtra et utilisera le canal par défaut. Encore une fois, définissez le canal temporaire à une chaîne vide, en veillant à placer cet extrait de code avant les dernières accolades finales.

```js
else{
  //If the user didnt put anything into the channel Input
  if(channel !== "Global"){
    //If the user isnt trying to navigate to the same channel theyre on
    setChannel("Global");
    let newURL = window.location.origin;
    window.history.pushState(null, '',newURL);
    tempChannel.setValue('');
  }
}
```

Nous ajoutons l'URL actuelle à l'historique du bouton "back" de notre navigateur afin de donner à nos utilisateurs la possibilité de naviguer vers les canaux précédents par ce biais. Pour que notre chat puisse réellement naviguer entre les canaux précédents à l'aide du bouton Précédent, nous devons effectuer quelques opérations supplémentaires.

Navigation entre les canaux précédents
--------------------------------------

Maintenant que nous avons mis en place toutes les fonctionnalités de notre salle de chat React, ajoutons une fonctionnalité pour re-rendre notre page. Nous allons changer notre état, au lieu de le recharger, lorsqu'un utilisateur clique pour revenir en arrière ou avancer entre nos pages.

Créez une fonction nommée goBack qui vérifie l'URL d'un canal et définit soit "Global", soit le canal trouvé pour l'état de notre canal. Cette fonction ne s'exécutera pas tant que nous n'aurons pas ajouté d'écouteurs d'événements à notre page !

```js
function goBack() {
  //Access the parameters provided in the URL
  let query = window.location.search.substring(1);
  if(!query){
    setChannel("Global")
  }else{
    let params = query.split("&");
    for(let i = 0; i < params.length;i++){
      var pair = params[i].split("=");
      //If the user input a channel then the default channel is now set
      //If not, we still navigate to the default channel.
      if(pair[0] === "channel" && pair[1] !== ""){
          setChannel(pair[1])
      }
    }
  }
}
```

Nous ne voulons ajouter l'écouteur qu'au chargement de la page, et le supprimer lorsque nous la quittons. Cela ressemble à une autre utilisation d'un crochet useEffect ! Créez-en un autre, mais passez un tableau vide comme second argument. Maintenant, ceci ne s'exécute qu'une seule fois lors du chargement initial de notre chat. Il ne s'exécutera pas à chaque rerendu.

Créez un event listener sur notre "window", et renvoyez une fonction de nettoyage qui supprime ce listener. L'écouteur d'événements attendra "popstate", c'est-à-dire le moment où l'utilisateur clique sur le bouton "back/forward" de son navigateur. Placez la dernière fonction que nous avons créée, "goBack", après le nom de l'événement. Désormais, notre page ne sera pas rechargée, elle restituera ce dont elle a besoin quand elle en a besoin !

```js
useEffect(() => {
  window.addEventListener("popstate",goBack);
  return function cleanup(){
    window.removeEventListener("popstate",goBack);
  }
},[]);
```

Utiliser JSX pour créer une interface utilisateur React
-------------------------------------------------------

Maintenant que nous avons complété toute la logique dont nous avons besoin dans notre backend, construisons un front-end simple mais moderne ! Pour ce faire, nous retournons [JSX](https://reactjs.org/docs/introducing-jsx.html), un langage de description d'interface utilisateur JavaScript. Il nous permet d'utiliser nos propres variables et objets à l'intérieur de groupes appelés composants. La syntaxe ressemble à du HTML avec un moteur de templating, mais c'est du JSX !

Lorsqu'une variable ou un état change, tout composant qui l'utilise est redessiné avec la nouvelle valeur. C'est ce qui rend notre application plus réactive, dès qu'il y a un changement, elle se met à jour. Pour cette raison, utiliser PubNub et React ensemble est une excellente idée. PubNub est capable de délivrer des messages rapidement et React suit en mettant à jour ses composants !

### Conception de l'application

Faisons maintenant le design de notre composant App. Material-UI nous fournit de beaux composants que nous pouvons utiliser et remplir avec nos propres informations. Utilisez le design suivant et nous verrons quelles fonctions sont appelées dans certaines zones.

```js
return(
  <Card >
    <CardContent>
      <div className="top">
        <Typography variant="h4" inline >
          PubNub React Chat
          </Typography>
        <Input
          style={{width:'100px'}}
          className="channel"
          id="channelInput"
          onKeyDown={handleKeyDown}
          placeholder ={channel}
          onChange = {tempChannel.onChange}
          value={tempChannel.value}
        />
      </div>
      <div >
        <Log messages={messages}/>
      </div>
    </CardContent>
    <CardActions>
      <Input
        placeholder="Enter a message"
        fullWidth={true}
        id="messageInput"
        value={tempMessage.value}
        onChange={tempMessage.onChange}
        onKeyDown={handleKeyDown}
        inputProps={{'aria-label': 'Message Field',}}
        autoFocus={true}
      />
      <Button
        size="small"
        color="primary"
        onClick={publishMessage}
        >
        Submit
      </Button>
    </CardActions>
  </Card>
);
```

Il peut sembler y avoir beaucoup de design ici, mais il s'agit d'organiser quelques éléments distincts.

Nous avons d'abord notre titre à l'intérieur d'un composant typographique. Ensuite, dans la même div, se trouve notre canal Input. Les entrées comprennent de nombreuses propriétés qui définissent les actions qu'elles peuvent entreprendre. Il s'agit notamment de son ID, de la fonction qui gère onKeyDown, de son espace réservé, de la fonction onChange et de sa valeur.

Il y a également des zones pour référencer ses styles. Après cette div, nous avons notre Log, un autre composant fonctionnel que nous n'avons pas encore créé. Ce journal prend notre tableau de messages et se réactualise à chaque fois que ce tableau change. Après notre journal, nous pouvons avoir une autre entrée et un bouton. L'entrée est l'endroit où l'utilisateur crée un message. Nous remplissons ses propriétés avec les états et les variables qu'il concerne.

Nous lui attribuons également la fonction de mise au point automatique. Réglez l'option onClick du bouton sur notre fonction de publication de message pour permettre aux utilisateurs d'envoyer leurs messages d'une autre manière. C'est la fin de notre composant App et le back-end est terminé. Nous devons maintenant créer deux autres petits composants pour afficher nos messages.

### Conception du journal et des messages

Notre application définit en grande partie le fonctionnement de notre chat, mais nous avons besoin de deux autres composants pour la compléter. Tous deux renvoient du JSX et organisent l'affichage de nos messages. Le premier, Log, affiche une liste de ListItems remplis de typographie. Ces ListItems parcourent une carte de nos messages et produisent un Message. Nous créons Message avec la clé de l'index dans le tableau, l'uuid du message et le texte du message.

```js
function Log(props) {
  return(
    <List component="nav">
      <ListItem>
      <Typography component="div">
        { props.messages.map((item, index)=>(
          <Message key={index} uuid={item.uuid} text={item.text}/>
        )) }
      </Typography>
      </ListItem>
    </List>
  )
};
```

Le composant Message représente un seul message, un élément div, rempli avec l'uuid et le texte, séparés par deux points. Les enfants de notre composant App accèdent aux messages par l'intermédiaire d'accessoires. Ils n'ont pas la possibilité d'éditer ou de modifier, mais seulement de lire et d'afficher ce qui leur est transmis.

Maintenant que nous avons défini nos composants, nous terminons notre application en l'exportant à la fin de notre fichier. Le code dans index.js rendra notre application sur la page web !Lancez

```js
npm start
```

dans notre dossier de projet et naviguez vers [localhost:3000](localhost:3000) dans notre navigateur pour voir notre application fonctionner !

```js
function Message(props){
  return (
    <div >
      { props.uuid }: { props.text }
    </div>
  );
}
export default App;
```

Voici un gif du chat en action :

[![react hooks chat gif](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1jkx/cadaa09d1dbce7a6f13e1fce08cc4a30/react-hooks-chat.gif)](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1jkx/cadaa09d1dbce7a6f13e1fce08cc4a30/react-hooks-chat.gif)

Nous avons réussi à créer une application qui permet aux utilisateurs de discuter dans les canaux de leur choix. Le [dépôt de code](https://github.com/PubNubDevelopers/ReactHooksChat.PubNub)complet est également[disponible ici](https://github.com/PubNubDevelopers/ReactHooksChat.PubNub).

Quelles sont les prochaines étapes ?
------------------------------------

Maintenant que vous avez mis en place votre fonctionnalité de messagerie de base, il est temps d'ajouter d'autres fonctionnalités ! Rendez-vous sur notre [page de solutions de chat](https://www.pubnub.com/solutions/chat/) pour découvrir de nouveaux tutoriels, les meilleures pratiques et les modèles de conception qui vous permettront de faire passer votre application de chat au niveau supérieur.

  
**Si le contenu intégré n'est pas disponible** sur cette page, il peut également être consulté à l'[adresse https://pubsub-quickstart-app.pubnub.com/signup](https://pubsub-quickstart-app.pubnub.com/signup).

#### Contenu

[Pub/Sub et récupération de l'historiquePour](#h-0)[commencerComment](#h-1)[installer React.js et PubNubPourquoi](#h-2)[utiliser React Hooks?](#h-3)[Créer un React Hook personnaliséConception de](#h-4)[nos composants ReactConfiguration](#h-5)[du composant App : State with React HooksuseEffect](#h-6)[in](#h-7) ReactInstaller[PubNub dans ReactPub/Sub](#h-8)[: PublishingCréer des](#h-9)[gestionnaires d'événements ReactNaviguer](#h-10)[entre les canaux précédentsUtiliser](#h-11)[JSX pour créer un UIApp](#h-12)[DesignLog](#h-13)[et Message DesignQu'est-ce](#h-14) qu'on fait[ensuite ?](#h-15)

Comment PubNub peut-il vous aider ?
===================================

Cet article a été publié à l'origine sur [PubNub.com](https://www.pubnub.com/blog/creating-a-chat-window-using-react-and-hooks/)

Notre plateforme aide les développeurs à construire, livrer et gérer l'interactivité en temps réel pour les applications web, les applications mobiles et les appareils IoT.

La base de notre plateforme est le réseau de messagerie en temps réel le plus grand et le plus évolutif de l'industrie. Avec plus de 15 points de présence dans le monde, 800 millions d'utilisateurs actifs mensuels et une fiabilité de 99,999 %, vous n'aurez jamais à vous soucier des pannes, des limites de concurrence ou des problèmes de latence causés par les pics de trafic.

Découvrez PubNub
----------------

Découvrez le [Live Tour](https://www.pubnub.com/tour/introduction/) pour comprendre les concepts essentiels de chaque application alimentée par PubNub en moins de 5 minutes.

S'installer
-----------

Créez un [compte PubNub](https://admin.pubnub.com/signup/) pour un accès immédiat et gratuit aux clés PubNub.

Commencer
---------

La [documentation PubNub](https://www.pubnub.com/docs) vous permettra de démarrer, quel que soit votre cas d'utilisation ou votre [SDK](https://www.pubnub.com/docs).