Utiliser Firebase avec React

Publié le 06 janvier 2017
#react# firebase# chat

Attention, cet article n'est pas à jour.

Avec React, vous savez persister les données de l'utilisateur, mais une nouvelle question se pose. Comment en partager une partie avec les autres utilisateurs? Dans le cadre d'un tchat par exemple?

C'est ce que nous allons voir en utilisant firebase.

Attention : un minimum de connaissances sur React est requis. Si vous ne connaissez pas encore React, c'est par ici que cela se passe : feuille-de-route-react :)

1. Firebase

Firebase est un outil qui fournit plusieurs services (authentification, base de données etc..). Ici nous allons nous intéresser au real-time database qui s'accorde parfaitement avec le concept de state de React :).

1.1. Configuration

Note : Si vous voulez passez cette étape (ne pas avoir votre propre compte Firebase), vous pouvez utiliser les informations contenues dans la section 1.2.

Dans un premier temps, allons sur la page d'accueil de Firebase est connectons nous avec un compte google.

Une fois cela fait, rendez-vous dans la console afin de créer le projet.

création du projet firebase
création du projet firebase

Maintenant que le projet est créé, il nous faut encore modifier les règles d'accès à la base de données, car, pour l'instant, celle-ci n'est accessible que lorsque l'utilisateur est authentifié, or nous n'avons pas besoin. Il nous faut donc modifier ces règles comme ceci :

modification des règles
modification des règles
Et la configuration est fini !

1.2. Récupération des informations de connexion

Cliquez sur l'onglet "Overview" du menu gauche afin d'accéder à l'icône "Ajouter firebase à votre application web". Cliquez sur celle-ci, puis, dans la fenêtre qui apparaît copiez la variable config, nous en aurons besoin plus tard.

récupération des informations de connexions à la base de données
récupération des informations de connexions à la base de données

Note : Vous pouvez utiliser mes informations, on pourra avoir le même tchat comme cela :D.

2. React

Maintenant que nous avons notre base de données, configurons notre application React afin de la synchroniser avec Firebase.

2.1. Installation du projet

Note: J'utilise ici yarn, qui est, dans l'ensemble, plus rapide que npm. Si vous voulez utiliser npm, voici une page listant les correspondances entre les commandes yarn que je vais utiliser et celle de npm : http://ricostacruz.com/cheatsheets/yarn.html.

Récupérons donc le projet react-chat-without-firebase que j'ai créé pour vous :

$ git clone https://github.com/gkueny/react-chat-without-firebase.git react-chat-with-firebase
$ cd react-chat-with-firebase
$ yarn

Afin d'utiliser firebase, nous allons également avoir besoin du package npm firebase. Ajoutons celui-ci à notre projet. (Et bien sûre, on n'oublie pas de lancer notre serveur ;) ).

$ yarn add firebase
$ yarn start

2.2. Mettons en place firebase

Bon... Là on a un beau tchat, mais il n'y a qu'un seul utilisateur possible. En plus si on supprime le state enregistré, pouf les messages disparaissent.

a. Connexion à firebase

Pour se connecter à notre base de données Firebase, nous allons utiliser notre variable config :

// File : src/index.js [EXTRAIT]

//...
import * as firebase from "firebase";
//...
// On retrouve notre variable config ;)
// Remplacez par la votre si vous voulez
const config = {
  apiKey: "AIzaSyA5pPKO8J9sR1m3hyPu7WJw2MzIu0z0q6o",
  authDomain: "react-tchat-e518d.firebaseapp.com",
  databaseURL: "https://react-tchat-e518d.firebaseio.com",
  storageBucket: "react-tchat-e518d.appspot.com",
  messagingSenderId: "640840838780"
};

firebase.initializeApp(config);
//...

b. Synchronisation avec firebase

Dans un premier temps, modifions la façon de gérer les messages. Nous allons les récupérer par Firebase. Du coup, au lieu de mettre à jour notre variable messages en y concaténant le nouveau message, nous allons la remplacer à chaque fois par les messages reçus de Firebase. Ce qui donne :

// File : src/actions/chat.actions.js

import { UPDATEMESSAGES } from "./actions.type";

export function updateMessage(messages) {
  return {
    type: UPDATEMESSAGES,
    data: {
      messages
    }
  };
}
// File : src/reducers/chat.reducer.js [EXTRAIT]

//..
const chatReducer = (state = initialState, action) => {
  switch (action.type) {
    case UPDATEMESSAGES: {
      return {
        ...state,
        messages: action.data.messages
      };
    }

    //..
  }
};

export default chatReducer;
// File : src/containers/chat.container.js [EXTRAIT]

//..
const mapDispatchToProps = dispatch => {
  return {
    updateMessage: messages => dispatch(updateMessage(messages))
  };
};
//...

Nous avons notre partie Redux prête pour la synchronisation avec Firebase. Maintenant il nous faut récupérer une référence à notre nouvelle base de données :

// File : src/components/chat.component.js [EXTRAIT]
import * as firebase from "firebase";
//..
class ChatComponent extends Component {
  constructor(props) {
    super(props);

    const rootRef = firebase.database().ref();
    this.messagesRef = rootRef.child("messages");

    this.state = {
      messageWriting: ""
    };
  }
  //...
}
//...

Mais attends... On récupère une référence vers "l'enfant" "messages" ? on ne l'a jamais créé dans Firebase non ?

Pas de souci ! Si "messages" n'existe pas, Firebase le créera.

Avec cette référence, nous allons pouvoir créer un listener qui sera appelé à chaque fois qu'un nouveau message est ajouté à Firebase :

// Fichier : src/components/chat.component.js [EXTRAIT]

//..
componentDidMount() {
    // notre listener
    this.messagesRef.on('value', snapshot => {

        let messages;

        // les valeurs de la base de données sont récupérables via snapshot.val()
        // On récupère ces données sous la forme [index] = value
        messages = snapshot.val() ? Object.keys(snapshot.val()).map( key => {
            return snapshot.val()[key];
        }) :
        messages = [];

        // On met à jour notre state à partir des messages récupérés de Firebase
        this.props.updateMessage(messages);
    });
}
// Et on supprime le listener lorsque le composant est détruit
componentWillUnmount() {
    this.messagesRef.on('value').off();
}
//..

Allez, dernière étape ! Envoyons notre nouveau message à Firebase :

// Fichier : src/components/chat.component.js [EXTRAIT]
//..
sendNewMessage = e => {
  e.preventDefault();

  // On ajoute une nouvelle entrée dans notre base de données et on récupère la clé correspondante
  const newMessageKey = this.messagesRef.push().key;

  // On décrit notre nouvelle entrée
  let updates = {};
  updates["/messages/" + newMessageKey] = {
    name: this.props.name,
    text: this.state.messageWriting
  };

  // On met à jour
  firebase
    .database()
    .ref()
    .update(updates);

  this.setState({
    messageWriting: ""
  });
};
//..

Plus besoin de mettre à jour notre state, car notre ajout entrainera l'appel de notre listener :D.

Finis ! Maintenant, nos messages sont synchronisés avec Firebase et ainsi tout les utilisateurs possèdent les mêmes messages.
gkueny

À propos de l'auteur - gkueny @ZEBet

Développeur depuis maintenant 6 ans, j'ai une grande affinité avec le mobile et les tests bien fait. Pas full-stack mais touche à tout, je suis également à l'aise sur du Symfony / php.