Wir haben uns bereits mit React Hooks beschäftigt, hier bei CSS-Tricks. Ich habe einen Artikel, der sie vorstellt, der auch veranschaulicht, wie man sie zur Erstellung von Komponenten durch Funktionen verwendet. Beide Artikel sind gute High-Level-Übersichten darüber, wie sie funktionieren, aber sie eröffnen auch viele Möglichkeiten.
Das werden wir also in diesem Artikel tun. Wir werden *sehen*, wie Hooks unseren Entwicklungsprozess einfacher und schneller machen, indem wir eine Chat-Anwendung erstellen.
Insbesondere erstellen wir eine Chat-Anwendung mit Create React App. Dabei werden wir eine Auswahl von React Hooks verwenden, um den Entwicklungsprozess zu vereinfachen und viel Boilerplate-Code zu entfernen, der für die Arbeit unnötig ist.
Es gibt mehrere Open-Source-React-Hooks, die wir ebenfalls nutzen werden. Diese Hooks können direkt genutzt werden, um Funktionen zu erstellen, die sonst mehr Code erfordert hätten. Sie folgen auch allgemein anerkannten Standards für jede Funktionalität. Dadurch wird die Effizienz beim Schreiben von Code erhöht und sichere Funktionalitäten bereitgestellt.
Schauen wir uns die Anforderungen an
Die Chat-Anwendung, die wir erstellen werden, wird die folgenden Funktionen haben
- Eine Liste vergangener Nachrichten vom Server abrufen
- Verbindung zu einem Raum für Gruppenchats herstellen
- Updates erhalten, wenn Personen einen Raum verlassen oder betreten
- Nachrichten senden und empfangen
Wir gehen von einigen Annahmen aus, während wir beginnen
- Wir werden den Server, den wir verwenden werden, als Blackbox betrachten. Machen Sie sich keine Sorgen, ob er perfekt funktioniert, da wir über einfache Sockets mit ihm kommunizieren werden.
- Alle Stile sind in einer einzigen CSS-Datei enthalten und können in das
src-Verzeichnis kopiert werden. Alle im App verwendeten Stile sind im Repository verlinkt.
Vorbereitung für die Arbeit
OK, wir wollen unsere Entwicklungsumgebung vorbereiten, um mit dem Schreiben von Code zu beginnen. Zunächst einmal benötigt React sowohl Node als auch npm. Sie können sie hier einrichten.
Lassen Sie uns ein neues Projekt im Terminal starten
npx create-react-app socket-client
cd socket-client
npm start
Jetzt sollten wir in der Lage sein, unter https://:3000 im Browser zu navigieren und die Standard-Willkommensseite für das Projekt zu sehen.
Von hier aus werden wir die Arbeit nach den Hooks aufteilen, die wir verwenden. Dies sollte uns helfen, die Hooks zu verstehen, während wir sie praktisch anwenden.
Verwendung des useState Hooks
Der erste Hook, den wir verwenden werden, ist useState. Er ermöglicht es uns, den Zustand innerhalb unserer Komponente zu verwalten, anstatt beispielsweise eine Klasse mit this.state schreiben und initialisieren zu müssen. Daten, die konstant bleiben, wie der Benutzername, werden in useState-Variablen gespeichert. Dies stellt sicher, dass die Daten leicht verfügbar bleiben und erfordert dabei deutlich weniger Code.
Der Hauptvorteil von useState ist, dass er automatisch in der gerenderten Komponente reflektiert wird, wann immer wir den Zustand der App aktualisieren. Wenn wir reguläre Variablen verwenden würden, würden diese nicht als Zustand der Komponente betrachtet werden und müssten als Props übergeben werden, um die Komponente neu zu rendern. Also schneiden wir wieder viel Arbeit aus und optimieren die Dinge dabei.
Der Hook ist direkt in React integriert, daher können wir ihn mit einer einzigen Zeile importieren
import React, { useState } from 'react';
Wir werden eine einfache Komponente erstellen, die "Hallo" zurückgibt, wenn der Benutzer bereits angemeldet ist, oder ein Anmeldeformular, wenn der Benutzer abgemeldet ist. Wir überprüfen dafür die id-Variable.
Unsere Formularübermittlungen werden von einer Funktion namens handleSubmit behandelt. Sie prüft, ob das Namensfeld ausgefüllt ist. Wenn ja, setzen wir die Werte id und room für diesen Benutzer. Andernfalls geben wir eine Meldung aus, die den Benutzer daran erinnert, dass das Namensfeld erforderlich ist, um fortzufahren.
// App.js
import React, { useState } from 'react';
import './index.css';
export default () => {
const [id, setId] = useState("");
const [nameInput, setNameInput] = useState("");
const [room, setRoom] = useState("");
const handleSubmit = e => {
e.preventDefault();
if (!nameInput) {
return alert("Name can't be empty");
}
setId(name);
socket.emit("join", name, room);
};
return id !== '' ? (
<div>Hello</div>
) : (
<div style={{ textAlign: "center", margin: "30vh auto", width: "70%" }}>
<form onSubmit={event => handleSubmit(event)}>
<input
id="name"
onChange={e => setNameInput(e.target.value.trim())}
required
placeholder="What is your name .."
/>
<br />
<input
id="room"
onChange={e => setRoom(e.target.value.trim())}
placeholder="What is your room .."
/>
<br />
<button type="submit">Submit</button>
</form>
</div>
);
};
So verwenden wir den useState-Hook in unserer Chat-Anwendung. Wiederum importieren wir den Hook aus React, erstellen Werte für die Benutzer-ID und den Chatraum, setzen diese Werte, wenn der Benutzer angemeldet ist, und geben ein Anmeldeformular zurück, wenn der Benutzer abgemeldet ist.

Verwendung des useSocket Hooks
Wir werden einen Open-Source-Hook namens useSocket verwenden, um eine Verbindung zu unserem Server aufrechtzuerhalten. Im Gegensatz zu useState ist dieser Hook nicht in React integriert, daher müssen wir ihn zu unserem Projekt hinzufügen, bevor wir ihn in die App importieren.
npm add use-socket.io-client
Die Serververbindung wird über die React Hooks-Version der socket.io-Bibliothek aufrechterhalten, was eine einfachere Methode ist, Websocket-Verbindungen mit einem Server aufrechtzuerhalten. Wir verwenden sie zum Senden und Empfangen von Echtzeitnachrichten sowie zur Verwaltung von Ereignissen, wie dem Beitritt zu einem Raum.
Die Standard-socket.io-Clientbibliothek hat globale Deklarationen, d.h. die von uns definierte Socket-Variable kann von jeder Komponente verwendet werden. Unsere Daten können jedoch von überall manipuliert werden und wir wissen nicht, woher diese Änderungen stammen. Socket-Hooks kontern dies, indem sie Hook-Definitionen auf Komponentenebene einschränken, was bedeutet, dass jede Komponente für ihre eigene Datenübertragung verantwortlich ist.
Die grundlegende Verwendung von useSocket sieht so aus
const [socket] = useSocket('socket-url')
Wir werden einige Socket-APIs verwenden, wenn wir weitermachen. Zur Referenz sind sie alle in der socket.io-Dokumentation aufgeführt. Aber vorerst importieren wir den Hook, da wir ihn bereits installiert haben.
import useSocket from 'use-socket.io-client';
Als Nächstes müssen wir den Hook initialisieren, indem wir uns mit unserem Server verbinden. Dann protokollieren wir den Socket in der Konsole, um zu überprüfen, ob er ordnungsgemäß verbunden ist.
const [id, setId] = useState('');
const [socket] = useSocket('<https://open-chat-naostsaecf.now.sh>');
socket.connect();
console.log(socket);
Öffnen Sie die Browserkonsole und die URL im Ausschnitt sollte protokolliert werden.
Verwendung des useImmer Hooks
Unsere Chat-App nutzt den useImmer Hook, um den Zustand von Arrays und Objekten zu verwalten, ohne den ursprünglichen Zustand zu verändern. Er kombiniert useState und Immer, um eine unveränderliche Zustandsverwaltung zu ermöglichen. Dies ist nützlich für die Verwaltung von Listen von Online-Personen und anzuzeigenden Nachrichten.
Die Verwendung von Immer mit useState ermöglicht es uns, ein Array oder Objekt zu ändern, indem wir einen neuen Zustand aus dem aktuellen Zustand erstellen und gleichzeitig Mutationen am aktuellen Zustand verhindern. Dies bietet uns mehr Sicherheit, indem wir den aktuellen Zustand intakt lassen und den Zustand basierend auf verschiedenen Bedingungen manipulieren können.
Auch hier arbeiten wir mit einem Hook, der nicht in React integriert ist. Importieren wir ihn also in das Projekt
npm add use-immer
Die grundlegende Verwendung ist ziemlich einfach. Der erste Wert im Konstruktor ist der aktuelle Zustand und der zweite Wert ist die Funktion, die diesen Zustand aktualisiert. Der useImmer Hook nimmt dann die Startwerte für den aktuellen Zustand.
const [data, setData] = useImmer(default_value)
Verwendung von setData
Beachten Sie die Funktion setData im letzten Beispiel? Wir verwenden sie, um eine Kopie der aktuellen Daten zu erstellen, die wir verwenden können, um die Daten sicher zu manipulieren und sie als nächsten Zustand zu verwenden, wenn Änderungen unveränderlich werden. Somit bleiben unsere ursprünglichen Daten erhalten, bis wir unsere Funktionen ausgeführt haben und es absolut klar ist, die aktuellen Daten zu aktualisieren.
setData(draftState => {
draftState.operation();
});
// ...or
setData(draft => newState);
// Here, draftState is a copy of the current data
Verwendung des useEffect Hooks
Alles klar, wir sind wieder bei einem Hook angelangt, der direkt in React integriert ist. Wir werden den useEffect Hook verwenden, um einen Codeabschnitt nur dann auszuführen, wenn die Anwendung geladen wird. Dies stellt sicher, dass unser Code nur einmal ausgeführt wird und nicht jedes Mal, wenn die Komponente mit neuen Daten neu gerendert wird, was gut für die Leistung ist.
Alles, was wir tun müssen, um den Hook zu verwenden, ist, ihn zu importieren – keine Installation erforderlich!
import React, { useState, useEffect } from 'react';
Wir benötigen eine Komponente, die eine Nachricht oder ein Update rendert, basierend auf dem Vorhandensein oder Fehlen einer Absender-ID im Array. Da wir kreative Leute sind, nennen wir diese Komponente Messages.
const Messages = props => props.data.map(m => m[0] !== '' ?
(<li key={m[0]}><strong>{m[0]}</strong> : <div className="innermsg">{m[1]}</div></li>)
: (<li key={m[1]} className="update">{m[1]}</li>) );
Lassen Sie uns unsere Socket-Logik in useEffect einfügen, damit wir nicht die gleichen Nachrichtensets wiederholt duplizieren, wenn eine Komponente neu gerendert wird. Wir definieren unseren Nachrichten-Hook in der Komponente, verbinden uns mit dem Socket und richten dann Listener für neue Nachrichten und Updates im useEffect Hook selbst ein. Wir werden auch Update-Funktionen innerhalb der Listener einrichten.
const [socket] = useSocket('<https://open-chat-naostsaecf.now.sh>');
socket.connect();
const [messages, setMessages] = useImmer([]);
useEffect(()=>{
socket.on('update', message => setMessages(draft => {
draft.push(['', message]);
}));
socket.on('message que',(nick, message) => {
setMessages(draft => {
draft.push([nick, message])
})
});
},0);
Als weiteren Leckerbissen fügen wir eine "Join"-Nachricht hinzu, wenn Benutzername und Raumname korrekt sind. Dies löst die restlichen Event-Listener aus und wir können vergangene Nachrichten, die in diesem Raum gesendet wurden, sowie alle erforderlichen Updates empfangen.
// ...
socket.emit('join', name, room);
};
return id ? (
<section style={{ display: "flex", flexDirection: "row" }}>
<ul id="messages">
<Messages data={messages} />
</ul>
<ul id="online">
{" "}
🌐 : <Online data={online} />{" "}
</ul>
<div id="sendform">
<form onSubmit={e => handleSend(e)} style={{ display: "flex" }}>
<input id="m" onChange={e => setInput(e.target.value.trim())} />
<button style={{ width: "75px" }} type="submit">
Send
</button>
</form>
</div>
</section>
) : (
// ...
Die letzten Schliff
Wir haben nur noch wenige Handgriffe, um unsere Chat-App fertigzustellen. Insbesondere brauchen wir noch
- Eine Komponente zur Anzeige von Online-Personen
- Einen
useImmerHook dafür mit einem Socket-Listener - Einen Nachrichtenübermittlungs-Handler mit entsprechenden Sockets
All dies baut auf dem auf, was wir bisher abgedeckt haben. Ich werde den vollständigen Code für die Datei App.js einfügen, um zu zeigen, wie alles zusammenpasst.
// App.js
import React, { useState, useEffect } from 'react';
import useSocket from 'use-socket.io-client';
import { useImmer } from 'use-immer';
import './index.css';
const Messages = props => props.data.map(m => m[0] !== '' ? (<li><strong>{m[0]}</strong> : <div className="innermsg">{m[1]}</div></li>) : (<li className="update">{m[1]}</li>) );
const Online = props => props.data.map(m => <li id={m[0]}>{m[1]}</li>);
export default () => {
const [id, setId] = useState('');
const [nameInput, setNameInput] = useState('');
const [room, setRoom] = useState('');
const [input, setInput] = useState('');
const [socket] = useSocket('https://open-chat-naostsaecf.now.sh');
socket.connect();
const [messages, setMessages] = useImmer([]);
const [online, setOnline] = useImmer([]);
useEffect(()=>{
socket.on('message que',(nick,message) => {
setMessages(draft => {
draft.push([nick,message])
})
});
socket.on('update',message => setMessages(draft => {
draft.push(['',message]);
}));
socket.on('people-list',people => {
let newState = [];
for(let person in people){
newState.push([people[person].id,people[person].nick]);
}
setOnline(draft=>{draft.push(...newState)});
console.log(online)
});
socket.on('add-person',(nick,id)=>{
setOnline(draft => {
draft.push([id,nick])
})
});
socket.on('remove-person',id=>{
setOnline(draft => draft.filter(m => m[0] !== id))
});
socket.on('chat message',(nick,message)=>{
setMessages(draft => {draft.push([nick,message])})
});
},0);
const handleSubmit = e => {
e.preventDefault();
if (!nameInput) {
return alert("Name can't be empty");
}
setId(name);
socket.emit("join", name,room);
};
const handleSend = e => {
e.preventDefault();
if(input !== ''){
socket.emit('chat message',input,room);
setInput('');
}
};
return id ? (
<section style={{display:'flex',flexDirection:'row'}} >
<ul id="messages"><Messages data={messages} /></ul>
<ul id="online"> 🌐 : <Online data={online} /> </ul>
<div id="sendform">
<form onSubmit={e => handleSend(e)} style={{display: 'flex'}}>
<input id="m" onChange={e=>setInput(e.target.value.trim())} /><button style={{width:'75px'}} type="submit">Send</button>
</form>
</div>
</section>
) : (
<div style={{ textAlign: 'center', margin: '30vh auto', width: '70%' }}>
<form onSubmit={event => handleSubmit(event)}>
<input id="name" onChange={e => setNameInput(e.target.value.trim())} required placeholder="What is your name .." /><br />
<input id="room" onChange={e => setRoom(e.target.value.trim())} placeholder="What is your room .." /><br />
<button type="submit">Submit</button>
</form>
</div>
);
};
Zusammenfassung
Das war's! Wir haben gemeinsam eine voll funktionsfähige Gruppenchat-Anwendung erstellt! Wie cool ist das denn? Der vollständige Code für das Projekt ist hier auf GitHub zu finden.
Was wir in diesem Artikel behandelt haben, ist lediglich ein Einblick, wie React Hooks Ihre Produktivität steigern und Ihnen helfen können, leistungsstarke Anwendungen mit leistungsstarken Front-End-Tools zu erstellen. Ich habe eine robustere Chat-Anwendung in diesem umfassenden Tutorial erstellt. Folgen Sie ihm, wenn Sie mit React Hooks noch weiter kommen möchten.
Jetzt, da Sie praktische Erfahrung mit React Hooks haben, nutzen Sie Ihr neu gewonnenes Wissen, um noch mehr zu üben! Hier sind einige Ideen, was Sie von nun an erstellen können
- Eine Blogging-Plattform
- Ihre eigene Version von Instagram
- Ein Klon von Reddit
Haben Sie Fragen auf dem Weg? Hinterlassen Sie einen Kommentar und lassen Sie uns gemeinsam großartige Dinge erschaffen.
Hallo Leser!
Sie können mich auf Twitter unter https://twitter.com/akashtrikon erreichen
Danke, dass Sie bis hierher gelesen haben
Sehr nützliche App von einer aufstrebenden, jungen und engagierten Person voller Ideen und Energie
Ich habe meinen Code mit Ihrem auf GitHub verglichen und ihn gemäß dem Tutorial geschrieben, aber er lässt sich nicht kompilieren und gibt die Fehlermeldung aus: 'Unexpected use of ‘name’ no restricted globals' in Zeile 66 und 67.
Können Sie mir helfen, herauszufinden, was los ist und wie ich es beheben kann?
Können Sie mich auf Twitter unter @akashtrikon erreichen?
Danke für die Information! Behoben im neuesten Commit! https://github.com/akash-joshi/fcc-socket-client
Ergebnisse
16306 hochriskante Schwachstellen gefunden
Außerdem Fehler: Unexpected use of ‘name’ no-restricted-globals
Beide Anweisungen hier und Klonen von GitHub ausprobiert.
Danke für die Information! Behoben im neuesten Commit! https://github.com/akash-joshi/fcc-socket-client
Bitte, welche IDE kann verwendet werden, um diese App zu erstellen?
Haftungsausschluss – Es gibt Fehler im obigen Code, Links zu mehreren Repos mit widersprüchlichen Versionen (Link zu
https://github.com/akash-joshi/socket-blog-client/tree/master/srcentfernen?), und einige Schritte, die impliziert, nicht explizit beschrieben sind. Wonameeinen Fehler verursacht, sollte es meiner Meinung nachnameInputsein?Auch
const [socket] = useSocket('<https://open-chat-naostsaecf.now.sh>');sollteconst [socket] = useSocket("https://open-chat-naostsaecf.now.sh");sein?Außerdem, sobald ich es geschafft habe, den Client zu verbinden, wird jede gesendete Nachricht dupliziert und erscheint zweimal in der Benutzeroberfläche. Ich bin mir nicht sicher, ob das passieren soll?
Hallo Rich! Stimme den ersten beiden Punkten zu, sie werden bald im Artikel berücksichtigt. Ich kann den Fehler im 3. Kommentar nicht reproduzieren. Können Sie mir einen GitHub-Link schicken und mich auf Twitter markieren, damit ich Ihnen antworten kann?