Ein Echtzeit-Chat-App mit React und Firebase bauen

Avatar of Deven Rathore
Deven Rathore am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

In diesem Artikel behandeln wir Schlüsselkonzepte zur Authentifizierung eines Benutzers mit Firebase in einer Echtzeit-Chat-Anwendung. Wir werden Drittanbieter-Authentifizierungsanbieter (z. B. Google, Twitter und GitHub) integrieren und, sobald sich Benutzer angemeldet haben, lernen, wie wir Benutzer-Chatdaten in der Firebase Realtime Database speichern können, wo wir Daten mit einer NoSQL-Cloud-Datenbank synchronisieren können.

Die Client-Anwendung wird in React erstellt, da es eines der beliebtesten JavaScript-Frameworks ist. Die Konzepte können jedoch auch auf andere Frameworks angewendet werden.

Aber zuerst: Was ist Firebase?

Firebase ist Googles mobile Plattform zur schnellen Entwicklung von Apps. Firebase bietet eine Reihe von Tools zur Authentifizierung von Anwendungen, zum Erstellen reaktiver Client-Apps, zur Analyse von Berichten sowie eine Vielzahl weiterer hilfreicher Ressourcen zur allgemeinen Verwaltung von Apps. Es bietet auch Back-End-Management für Web, iOS, Android und Unity, eine 3D-Entwicklungsplattform.

Standardmäßig ist Firebase mit Funktionen ausgestattet, die Entwicklern wie uns helfen, sich auf die Entwicklung von Apps zu konzentrieren, während es die gesamte serverseitige Logik übernimmt. Dinge wie

  • Authentifizierung: Dies beinhaltet die Unterstützung für E-Mail- und Passwort-Authentifizierung sowie Single-Sign-On-Funktionen (über Facebook, Twitter und Google).
  • Echtzeitdatenbank: Dies ist eine "NoSQL"-Datenbank, die sich in Echtzeit aktualisiert.
  • Cloud-Funktionen: Diese führen zusätzliche serverseitige Logik aus.
  • Statische Hosting: Dies ist ein Mittel, um vorab erstellte Assets bereitzustellen, anstatt sie zur Laufzeit zu rendern.
  • Cloud Storage: Dies bietet uns einen Ort zur Speicherung von Medieninhalten.

Firebase bietet einen großzügigen kostenlosen Tarif, der Authentifizierung und Zugriff auf seine Realtime Database beinhaltet. Die Authentifizierungsanbieter, die wir behandeln werden – E-Mail und Passwort sowie Google und GitHub – sind auf dieser Seite ebenfalls kostenlos. Die Realtime Database erlaubt bis zu 100 gleichzeitige Verbindungen und 1 Gigabyte Speicher pro Monat. Eine vollständige Preisübersicht finden Sie auf der Firebase-Website.

Das erstellen wir

Wir werden eine Anwendung namens Chatty erstellen. Sie wird es nur authentifizierten Benutzern ermöglichen, Nachrichten zu senden und zu lesen, und Benutzer können sich registrieren, indem sie ihre E-Mail-Adresse angeben und ein Passwort erstellen, oder indem sie sich über ein Google- oder GitHub-Konto authentifizieren. Schauen Sie sich den Quellcode an, wenn Sie ihn referenzieren möchten oder einen Blick darauf werfen möchten, während wir beginnen.

Am Ende werden wir etwas Ähnliches wie dies haben

Einrichtung

Sie benötigen ein Google-Konto, um Firebase nutzen zu können. Besorgen Sie sich also eines, falls Sie noch keines haben. Und sobald Sie das getan haben, können wir offiziell mit diesem Ding loslegen.

Gehen Sie zuerst zur Firebase Console und klicken Sie auf die Option „Projekt hinzufügen“.

Geben Sie als Nächstes einen Namen für das Projekt ein. Ich wähle Chatty.

Sie können Ihrem Projekt Analysen hinzufügen, aber es ist nicht erforderlich. Klicken Sie in jedem Fall auf „Weiter“, um fortzufahren, und Firebase benötigt einige Sekunden, um Ressourcen für das Projekt zuzuweisen.

Sobald dies hochgefahren ist, gelangen wir zum Firebase-Dashboard. Bevor wir Firebase jedoch in unserer Web-App verwenden können, müssen wir die Konfigurationsdetails für unser Projekt festhalten. Klicken Sie also auf das Websymbol im Dashboard.

Geben Sie dann einen Namen für die App ein und klicken Sie auf App registrieren.

Als Nächstes kopieren wir die Konfigurationsdetails auf dem nächsten Bildschirm und speichern sie an einem sicheren Ort. Das wird im nächsten Schritt nützlich sein.

Auch hier werden wir Benutzer über E-Mail und Passwort authentifizieren, mit zusätzlichen Optionen für Single-Sign-On mit einem Google- oder GitHub-Konto. Wir müssen diese über den Authentifizierungs-Tab im Dashboard aktivieren, aber wir werden jeden einzelnen nacheinander durchgehen.

E-Mail- und Passwort-Authentifizierung

Im Firebase-Dashboard gibt es einen Tab namens Anmeldemethode. Klicken Sie auf die Option E-Mail/Passwort und aktivieren Sie sie.

Jetzt können wir es in unserer App verwenden!

Einrichtung der Web-App

Für unsere Web-App werden wir React verwenden, aber die meisten Konzepte können auf jedes andere Framework angewendet werden. Wir benötigen Node.js für eine React-Einrichtung, also laden Sie es herunter und installieren Sie es, falls Sie das noch nicht getan haben.

Wir werden create-react-app verwenden, um ein neues React-Projekt zu bootstrappen. Dies lädt die notwendigen Pakete herunter und installiert sie, die für eine React-Anwendung erforderlich sind. Wechseln Sie im Terminal zu dem Verzeichnis, in dem Ihr Chatty-Projekt platziert werden soll, und führen Sie dies aus, um es zu initialisieren

npx create-react-app chatty

Dieser Befehl führt die Erstkonfiguration für unsere React-App durch und installiert die Abhängigkeiten in package.json. Wir werden auch einige zusätzliche Pakete installieren. Wechseln wir also in das Projekt selbst und fügen wir Pakete für React Router und Firebase hinzu.

cd chatty
yarn add react-router-dom firebase

Wir wissen bereits, warum wir Firebase brauchen, aber warum React Router? Unsere Chat-App wird ein paar Ansichten haben, wir können React Router verwenden, um die Navigation zwischen Seiten zu handhaben.

Damit ist das erledigt, wir können die App offiziell starten

yarn start

Dies startet einen Entwicklungsserver und öffnet eine URL in Ihrem Standardbrowser. Wenn alles korrekt installiert wurde, sollten Sie einen Bildschirm wie diesen sehen

Wenn Sie sich die Ordnerstruktur ansehen, würden Sie etwas Ähnliches wie dieses sehen

Für unsere Chat-App werden wir diese Ordnerstruktur verwenden

  • /components: enthält wiederverwendbare Widgets, die auf verschiedenen Seiten verwendet werden
  • /helpers: ein Satz wiederverwendbarer Funktionen
  • /pages: die App-Ansichten
  • /services: Drittanbieterdienste, die wir verwenden (z. B. Firebase)
  • App.js: die Root-Komponente

Alles andere im Ordner ist für dieses Projekt unnötig und kann sicher entfernt werden. Von hier aus fügen wir Code zu src/services/firebase.js hinzu, damit die App mit Firebase kommunizieren kann.

import firebase from 'firebase';

Holen wir Firebase in die App

Wir werden Firebase mit den Konfigurationsdetails, die wir zuvor bei der Registrierung der App im Firebase-Dashboard kopiert haben, importieren und initialisieren. Dann werden wir die Authentifizierungs- und Datenbankmodule exportieren.

const config = {
  apiKey: "ADD-YOUR-DETAILS-HERE",
  authDomain: "ADD-YOUR-DETAILS-HERE",
  databaseURL: "ADD-YOUR-DETAILS-HERE"
};
firebase.initializeApp(config);
export const auth = firebase.auth;
export const db = firebase.database();

Importieren wir unsere Abhängigkeiten in src/App.js

import React, { Component } from 'react';
import {
  Route,
  BrowserRouter as Router,
  Switch,
  Redirect,
} from "react-router-dom";
import Home from './pages/Home';
import Chat from './pages/Chat';
import Signup from './pages/Signup';
import Login from './pages/Login';
import { auth } from './services/firebase';

Dies sind ES6-Importe. Speziell importieren wir React und andere Pakete, die zum Aufbau der App benötigt werden. Wir importieren auch alle Seiten unserer App, die wir später für unseren Router konfigurieren werden.

Als Nächstes kommt das Routing

Unsere App hat öffentliche Routen (zugänglich ohne Authentifizierung) und eine private Route (nur mit Authentifizierung zugänglich). Da React keine Möglichkeit bietet, den authentifizierten Status zu überprüfen, werden wir Higher-Order Components (HOCs) für beide Routentypen erstellen.

Unsere HOCs werden

  • einen <Route> umschließen,
  • Props vom Router an die <Route> weitergeben,
  • die Komponente basierend auf dem Authentifizierungsstatus rendern, und
  • den Benutzer zu einer angegebenen Route weiterleiten, wenn die Bedingung nicht erfüllt ist

Schreiben wir den Code für unser <PrivateRoute> HOC.

function PrivateRoute({ component: Component, authenticated, ...rest }) {
  return (
    <Route
      {...rest}
      render={(props) => authenticated === true
        ? <Component {...props} />
        : <Redirect to={{ pathname: '/login', state: { from: props.location } }} />}
    />
  )
}

Es empfängt drei Props: die zu rendernde Komponente, wenn die Bedingung wahr ist, den authenticated-Status und den ES6-Spread-Operator, um die restlichen Parameter zu erhalten, die vom Router übergeben werden. Es prüft, ob authenticated wahr ist und rendert die übergebene Komponente, andernfalls wird zu /login weitergeleitet.

function PublicRoute({ component: Component, authenticated, ...rest }) {
  return (
    <Route
      {...rest}
      render={(props) => authenticated === false
        ? <Component {...props} />
        : <Redirect to='/chat' />}
    />
  )
}

Die <PublicRoute> ist praktisch identisch. Sie rendert unsere öffentlichen Routen und leitet zum Pfad /chat weiter, wenn der Authentifizierungsstatus wahr wird. Wir können die HOCs in unserer Render-Methode verwenden

render() {
  return this.state.loading === true ? <h2>Loading...</h2> : (
    <Router>
      <Switch>
        <Route exact path="/" component={Home}></Route>
        <PrivateRoute path="/chat" authenticated={this.state.authenticated} component={Chat}></PrivateRoute>
        <PublicRoute path="/signup" authenticated={this.state.authenticated} component={Signup}></PublicRoute>
        <PublicRoute path="/login" authenticated={this.state.authenticated} component={Login}></PublicRoute>
      </Switch>
    </Router>
  );
}

Prüfung auf Authentifizierung

Es wäre gut, eine Ladeanzeige anzuzeigen, während wir überprüfen, ob der Benutzer authentifiziert ist. Sobald die Prüfung abgeschlossen ist, rendern wir die entsprechende Route, die der URL entspricht. Wir haben drei öffentliche Routen – <Home>, <Login> und <Signup> – und eine private namens <Chat>.

Schreiben wir die Logik, um zu prüfen, ob der Benutzer tatsächlich authentifiziert ist.

class App extends Component {
  constructor() {
    super();
    this.state = {
      authenticated: false,
      loading: true,
    };
  }
}

export default App;

Hier setzen wir den anfänglichen Zustand der App. Dann verwenden wir den componentDidMount Lifecycle Hook, um zu prüfen, ob der Benutzer authentifiziert ist. Fügen wir dies also nach dem Konstruktor hinzu

componentDidMount() {
  auth().onAuthStateChanged((user) => {
    if (user) {
      this.setState({
        authenticated: true,
        loading: false,
      });
    } else {
      this.setState({
        authenticated: false,
        loading: false,
      });
    }
  })
}

Firebase stellt eine intuitive Methode namens onAuthStateChanged bereit, die ausgelöst wird, wenn sich der Authentifizierungsstatus ändert. Wir verwenden diese, um unseren anfänglichen Zustand zu aktualisieren. user ist null, wenn der Benutzer nicht authentifiziert ist. Wenn user wahr ist, aktualisieren wir authenticated auf true; andernfalls setzen wir es auf false. Wir setzen auch loading auf false, egal was passiert.

Benutzer mit E-Mail und Passwort registrieren

Benutzer können sich bei Chatty per E-Mail und Passwort registrieren. Der Ordner helpers enthält eine Reihe von Methoden, die wir zur Handhabung einiger Authentifizierungslogik verwenden werden. Erstellen Sie in diesem Ordner eine neue Datei namens auth.js und fügen Sie dies hinzu

import { auth } from "../services/firebase";

Wir importieren das Authentifizierungsmodul aus dem zuvor erstellten Dienst.

export function signup(email, password) {
  return auth().createUserWithEmailAndPassword(email, password);
}


export function signin(email, password) {
  return auth().signInWithEmailAndPassword(email, password);
}

Wir haben hier zwei Methoden: signup und signin

  • signup erstellt einen neuen Benutzer anhand seiner E-Mail-Adresse und seines Passworts.
  • signin meldet einen bestehenden Benutzer an, der mit E-Mail und Passwort erstellt wurde.

Erstellen wir unsere <Signup>-Seite, indem wir eine neue Datei Signup.js im Seitenordner erstellen. Dies ist das Markup für die Benutzeroberfläche

import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { signup } from '../helpers/auth';


export default class SignUp extends Component {


  render() {
    return (
      <div>
        <form onSubmit={this.handleSubmit}>
          <h1>
            Sign Up to
          <Link to="/">Chatty</Link>
          </h1>
          <p>Fill in the form below to create an account.</p>
          <div>
            <input placeholder="Email" name="email" type="email" onChange={this.handleChange} value={this.state.email}></input>
          </div>
          <div>
            <input placeholder="Password" name="password" onChange={this.handleChange} value={this.state.password} type="password"></input>
          </div>
          <div>
            {this.state.error ? <p>{this.state.error}</p> : null}
            <button type="submit">Sign up</button>
          </div>
          <hr></hr>
          <p>Already have an account? <Link to="/login">Login</Link></p>
        </form>
      </div>
    )
  }
}
E-Mail? Check. Passwort? Check. Senden-Schaltfläche? Check. Unser Formular sieht gut aus.

Das Formular und die Eingabefelder sind an eine Methode gebunden, die wir noch nicht erstellt haben. Sortieren wir das also aus. Kurz vor der render()-Methode fügen wir Folgendes hinzu

constructor(props) {
  super(props);
  this.state = {
    error: null,
    email: '',
    password: '',
  };
  this.handleChange = this.handleChange.bind(this);
  this.handleSubmit = this.handleSubmit.bind(this);
}

Wir setzen den anfänglichen Zustand der Seite. Wir binden auch die Methoden handleChange und handleSubmit an den Gültigkeitsbereich des `this`-Objekts der Komponente.

handleChange(event) {
  this.setState({
    [event.target.name]: event.target.value
  });
}

Als Nächstes fügen wir die Methode handleChange hinzu, an die unsere Eingabefelder gebunden sind. Die Methode verwendet berechnete Eigenschaften, um den Schlüssel dynamisch zu bestimmen und die entsprechende Zustandsvariable festzulegen.

async handleSubmit(event) {
  event.preventDefault();
  this.setState({ error: '' });
  try {
    await signup(this.state.email, this.state.password);
  } catch (error) {
    this.setState({ error: error.message });
  }
}

Bei handleSubmit verhindern wir das Standardverhalten von Formularübermittlungen (das unter anderem den Browser neu lädt). Wir bereinigen die Fehlersatzvariable und verwenden dann die aus helpers/auth importierte signup()-Methode, um die vom Benutzer eingegebene E-Mail und das Passwort zu übergeben.

Wenn die Registrierung erfolgreich ist, werden die Benutzer zur Route /Chats weitergeleitet. Dies ist möglich durch die Kombination von onAuthStateChanged und den zuvor erstellten HOCs. Wenn die Registrierung fehlschlägt, setzen wir die Fehlervariable, die dem Benutzer eine Nachricht anzeigt.

Benutzer mit E-Mail und Passwort authentifizieren

Die Login-Seite ist identisch mit der Signup-Seite. Der einzige Unterschied ist, dass wir die signin-Methode aus den zuvor erstellten Hilfsmitteln verwenden werden. Erstellen wir also eine weitere neue Datei im Seitenverzeichnis, diesmal mit dem Namen Login.js, und fügen Sie diesen Code hinzu

import React, { Component } from "react";
import { Link } from "react-router-dom";
import { signin, signInWithGoogle, signInWithGitHub } from "../helpers/auth";


export default class Login extends Component {
  constructor(props) {
    super(props);
    this.state = {
      error: null,
      email: "",
      password: ""
    };
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }


  handleChange(event) {
    this.setState({
      [event.target.name]: event.target.value
    });
  }


  async handleSubmit(event) {
    event.preventDefault();
    this.setState({ error: "" });
    try {
      await signin(this.state.email, this.state.password);
    } catch (error) {
      this.setState({ error: error.message });
    }
  }


  render() {
    return (
      <div>
        <form
          autoComplete="off"
          onSubmit={this.handleSubmit}
        >
          <h1>
            Login to
            <Link to="/">
              Chatty
            </Link>
          </h1>
          <p>
            Fill in the form below to login to your account.
          </p>
          <div>
            <input
              placeholder="Email"
              name="email"
              type="email"
              onChange={this.handleChange}
              value={this.state.email}
            />
          </div>
          <div>
            <input
              placeholder="Password"
              name="password"
              onChange={this.handleChange}
              value={this.state.password}
              type="password"
            />
          </div>
          <div>
            {this.state.error ? (
              <p>{this.state.error}</p>
            ) : null}
            <button type="submit">Login</button>
          </div>
          <hr />
          <p>
            Don't have an account? <Link to="/signup">Sign up</Link>
          </p>
        </form>
      </div>
    );
  }
}

Wiederum sehr ähnlich wie zuvor. Wenn sich der Benutzer erfolgreich anmeldet, wird er zu /chat weitergeleitet.

Authentifizierung mit einem Google-Konto

Firebase ermöglicht es uns, Benutzer mit einem gültigen Google-Konto zu authentifizieren. Wir müssen es im Firebase-Dashboard aktivieren, genau wie wir es für E-Mail und Passwort getan haben.

Wählen Sie die Option Google und aktivieren Sie sie in den Einstellungen.

Auf derselben Seite müssen wir auch nach unten scrollen, um eine Domain zur Liste der Domains hinzuzufügen, die zur Funktion berechtigt sind. Auf diese Weise vermeiden wir Spam von jeder Domain, die nicht auf der Whitelist steht. Zu Entwicklungszwecken ist unsere Domain localhost, also bleiben wir vorerst dabei.

Wir können jetzt zurück zu unserem Editor wechseln. Wir werden eine neue Methode zu helpers/auth.js hinzufügen, um die Google-Authentifizierung zu handhaben.

export function signInWithGoogle() {
  const provider = new auth.GoogleAuthProvider();
  return auth().signInWithPopup(provider);
}

Hier erstellen wir eine Instanz von GoogleAuthProvider. Dann rufen wir signInWithPopup mit dem Anbieter als Parameter auf. Wenn diese Methode aufgerufen wird, erscheint ein Popup, das den Benutzer durch den Google-Anmeldevorgang führt, bevor er zur App zurückgeleitet wird. Sie haben das wahrscheinlich schon einmal selbst erlebt.

Verwenden wir es auf unserer Signup-Seite, indem wir die Methode importieren

import { signin, signInWithGoogle } from "../helpers/auth";

Fügen wir dann einen Button hinzu, um die Methode auszulösen, direkt unter dem Button Registrieren

<p>Or</p>
<button onClick={this.googleSignIn} type="button">
  Sign up with Google
</button>

Als Nächstes fügen wir den onClick-Handler hinzu

async googleSignIn() {
  try {
    await signInWithGoogle();
  } catch (error) {
    this.setState({ error: error.message });
  }
}

Oh, und wir sollten nicht vergessen, den Handler an die Komponente zu binden

constructor() {
  // ...
  this.githubSignIn = this.githubSignIn.bind(this);
}

Das ist alles, was wir brauchen! Wenn der Button geklickt wird, führt er die Benutzer durch den Google-Anmeldevorgang und, wenn erfolgreich, leitet die App den Benutzer zur Chat-Route weiter.

Authentifizierung mit einem GitHub-Konto

Das Gleiche machen wir auch mit GitHub. Geben wir den Leuten ruhig mehr als eine Auswahl an Konten.

Lassen Sie uns die Schritte durchgehen. Zuerst aktivieren wir die GitHub-Anmeldung im Firebase-Dashboard, genau wie bei E-Mail und Google.

Sie werden feststellen, dass sowohl die Felder Client-ID als auch Client-Secret leer sind, aber wir haben unsere autorisierte Callback-URL unten. Kopieren Sie diese, denn wir werden sie verwenden, wenn wir unser nächstes Ding tun, nämlich die App auf GitHub registrieren.

Sobald das erledigt ist, erhalten wir eine Client-ID und ein Secret, die wir nun in die Firebase-Konsole einfügen können.

Wechseln wir zurück zum Editor und fügen eine neue Methode zu helpers/auth.js hinzu

export function signInWithGitHub() {
  const provider = new auth.GithubAuthProvider();
  return auth().signInWithPopup(provider);
}

Es ist ähnlich wie die Google-Anmeldeschnittstelle, aber diesmal erstellen wir einen GithubAuthProvider. Dann rufen wir signInWithPopup mit dem Anbieter auf.

In pages/Signup.js aktualisieren wir unsere Importe, um die Methode signInWithGitHub aufzunehmen

import { signup, signInWithGoogle, signInWithGitHub } from "../helpers/auth";

Wir fügen einen Button für die GitHub-Anmeldung hinzu

<button type="button" onClick={this.githubSignIn}>
  Sign up with GitHub
</button>

Dann fügen wir einen Klick-Handler für den Button hinzu, der den GitHub-Anmeldevorgang auslöst

async githubSignIn() {
  try {
    await signInWithGitHub();
  } catch (error) {
    this.setState({ error: error.message });
  }
}

Denken wir auch hier daran, den Handler an die Komponente zu binden

constructor() {
  // ...
  this.githubSignIn = this.githubSignIn.bind(this);
}

Jetzt erhalten wir denselben Anmelde- und Authentifizierungsvorgang wie bei Google, aber mit GitHub.

Daten aus Firebase lesen

Firebase hat zwei Arten von Datenbanken: Ein Produkt namens Realtime Database und ein anderes namens Cloud Firestore. Beide Datenbanken sind NoSQL-ähnliche Datenbanken, was bedeutet, dass die Datenbank als Schlüssel-Wert-Paare strukturiert ist. Für dieses Tutorial verwenden wir die Realtime Database.

Dies ist die Struktur, die wir für unsere App verwenden werden. Wir haben einen Root-Knoten chats mit Kindknoten. Jedes Kind hat einen Inhalt, einen Zeitstempel und eine Benutzer-ID. Einer der Tabs, den Sie bemerken werden, sind Regeln, mit denen wir Berechtigungen für den Inhalt der Datenbank festlegen.

Firebase-Datenbankregeln werden ebenfalls als Schlüssel-Wert-Paare definiert. Hier legen wir unsere Regeln fest, um nur authentifizierten Benutzern das Lesen und Schreiben in den Chat-Knoten zu gestatten. Es gibt viele weitere Firebase-Regeln, die es wert sind, sie sich anzusehen.

Schreiben wir Code, um aus der Datenbank zu lesen. Erstellen Sie zuerst eine neue Datei namens Chat.js im Seitenordner und fügen Sie diesen Code hinzu, um React, Firebase-Authentifizierung und die Echtzeitdatenbank zu importieren

import React, { Component } from "react";
import { auth } from "../services/firebase";
import { db } from "../services/firebase"

Als Nächstes definieren wir den anfänglichen Zustand der App

export default class Chat extends Component {
  constructor(props) {
    super(props);
    this.state = {
      user: auth().currentUser,
      chats: [],
      content: '',
      readError: null,
      writeError: null
    };
  }
  async componentDidMount() {
    this.setState({ readError: null });
    try {
      db.ref("chats").on("value", snapshot => {
        let chats = [];
        snapshot.forEach((snap) => {
          chats.push(snap.val());
        });
        this.setState({ chats });
      });
    } catch (error) {
      this.setState({ readError: error.message });
    }
  }
}

Die eigentliche Hauptlogik findet in componentDidMount statt. db.ref("chats") ist eine Referenz auf den Chat-Pfad in der Datenbank. Wir lauschen auf das Wert-Ereignis, das jedes Mal ausgelöst wird, wenn ein neuer Wert zum Chat-Knoten hinzugefügt wird. Was aus der Datenbank zurückgegeben wird, ist ein Array-ähnliches Objekt, das wir durchlaufen und jedes Objekt in ein Array pushen. Dann setzen wir die chats-Zustandsvariable auf unser Ergebnis-Array. Wenn ein Fehler auftritt, setzen wir die readError-Zustandsvariable auf die Fehlermeldung.

Eine Sache, die hier zu beachten ist, ist, dass eine Verbindung zwischen dem Client und unserer Firebase-Datenbank hergestellt wird, weil wir die .on()-Methode verwendet haben. Das bedeutet, dass die Client-App jedes Mal, wenn ein neuer Wert zur Datenbank hinzugefügt wird, in Echtzeit aktualisiert wird, was bedeutet, dass Benutzer neue Chats ohne Seitenaktualisierung sehen können. Nett!

Nach componentDidMount können wir unsere Chats wie folgt rendern

render() {
  return (
    <div>
      <div className="chats">
        {this.state.chats.map(chat => {
          return <p key={chat.timestamp}>{chat.content}</p>
        })}
      </div>
      <div>
        Login in as: <strong>{this.state.user.email}</strong>
      </div>
    </div>
  );
}

Dies rendert das Array von Chats. Wir rendern die E-Mail des aktuell angemeldeten Benutzers.

Daten in Firebase schreiben

Derzeit können Benutzer nur aus der Datenbank lesen, sind aber nicht in der Lage, Nachrichten zu senden. Was wir brauchen, ist ein Formular mit einem Eingabefeld, das eine Nachricht akzeptiert, und einer Schaltfläche, um die Nachricht an den Chat zu senden.

Modifizieren wir also das Markup wie folgt

return (
    <div>
      <div className="chats">
        {this.state.chats.map(chat => {
          return <p key={chat.timestamp}>{chat.content}</p>
        })}
      </div>
      {# message form #}
      <form onSubmit={this.handleSubmit}>
        <input onChange={this.handleChange} value={this.state.content}></input>
        {this.state.error ? <p>{this.state.writeError}</p> : null}
        <button type="submit">Send</button>
      </form>
      <div>
        Login in as: <strong>{this.state.user.email}</strong>
      </div>
    </div>
  );
}

Wir haben ein Formular mit einem Eingabefeld und einer Schaltfläche hinzugefügt. Der Wert des Eingabefeldes ist an unsere Zustandsvariable content gebunden, und wir rufen handleChange auf, wenn sich sein Wert ändert.

handleChange(event) {
  this.setState({
    content: event.target.value
  });
}

handleChange holt den Wert aus dem Eingabefeld und setzt ihn auf unsere Zustandsvariable. Zum Absenden des Formulars rufen wir handleSubmit auf

async handleSubmit(event) {
  event.preventDefault();
  this.setState({ writeError: null });
  try {
    await db.ref("chats").push({
      content: this.state.content,
      timestamp: Date.now(),
      uid: this.state.user.uid
    });
    this.setState({ content: '' });
  } catch (error) {
    this.setState({ writeError: error.message });
  }
}

Wir setzen alle vorherigen Fehler auf null. Wir erstellen eine Referenz auf den chats-Knoten in der Datenbank und verwenden push(), um einen eindeutigen Schlüssel zu erstellen und das Objekt dorthin zu pushen.

Wie immer müssen wir unsere Methoden an die Komponente binden

constructor(props) {
  // ...
  this.handleChange = this.handleChange.bind(this);
  this.handleSubmit = this.handleSubmit.bind(this);
}

Jetzt kann ein Benutzer neue Nachrichten zu den Chats hinzufügen und sie in Echtzeit sehen! Wie cool ist das?

Demo!

Genießen Sie Ihre neue Chat-App!

Glückwunsch! Sie haben gerade ein Chat-Tool erstellt, das Benutzer mit E-Mail und Passwort authentifiziert, zusammen mit Optionen zur Authentifizierung über ein Google- oder GitHub-Konto.

Ich hoffe, dies gibt Ihnen eine gute Vorstellung davon, wie praktisch Firebase sein kann, um mit der Authentifizierung in einer App loszulegen. Wir haben an einer Chat-App gearbeitet, aber das wahre Juwel sind die Registrierungs- und Anmeldemethoden, die wir entwickelt haben, um darauf zuzugreifen. Das ist für viele Apps nützlich.

Fragen? Gedanken? Feedback? Lassen Sie es mich in den Kommentaren wissen!