Dans ce tutoriel, vous apprendrez à créer une application de chat avec React et Chatkit.
Lorsque nous aurons terminé, nous aurons une application de chat complète avec des indicateurs de dactylographie , une liste "qui est en ligne" et l'historique des messages :

Si vous pensez que cela semble beaucoup à aborder dans un seul tutoriel, vous auriez normalement raison!
Cependant, parce que nous utiliserons Chatkit, nous pouvons nous concentrer plus ou moins exclusivement sur le code de réaction frontal tandis que Chatkit fait le travail lourd.
Chatkit est une API hébergée qui vous aide à créer des fonctionnalités de chat impressionnantes dans vos applications avec moins de code. Des fonctionnalités comme,
En utilisant nos SDK multiplateformes, toutes les données de chat sont envoyées à notre API hébergée où nous gérons l'état de chat et les diffusons à vos clients:

Vous n'aurez jamais à vous soucier de l'échelle ou de l'infrastructure, nous nous occupons de tout cela pour vous.
Peut-être que la meilleure façon d'apprendre le chatkit est de commencer à construire, donc je vous recommande fortement de suivre. En cours de route, vous apprendrez les meilleures pratiques lorsque vous utilisez Chatkit avec React.
Ce tutoriel a été écrit afin que vous puissiez suivre, étape par étape. Il y a 12 étapes au total.
Voici un aperçu rapide pour savoir à quoi vous attendre:
Très bien, codes!
Plutôt que de commencer à zéro absolu, cette procédure pas à pas est basée sur un modèle de démarrage minimal:

Comme vous pouvez le voir, le modèle de démarrage ne contient aucune logique intéressante - juste la baillire, nous devons exécuter une application React et un serveur de nœuds simples.
"Serveur? Personne n'a mentionné un serveur!"
Si vous n'êtes pas trop familier avec Node, ne vous inquiétez pas ?. Après la section suivante, nous n'aurons pas besoin de toucher le serveur.
Pour commencer, téléchargez le modèle de démarrage, puis exécutez npm install :
git clone https://github.com/pusher/build-a-slack-clone-with-react-and-pusher-chatkit chatkit-tutorial
cd chatkit-tutorial
npm install
(Remarque: Pour voir le code terminé, vous pouvez afficher la branche completed ou exécuter git checkout complete localement.)
(Remarque: ce tutoriel suppose l'utilisation de npm , mais les commandes yarn équivalent fonctionneront également.)
Maintenant, vous avez téléchargé le modèle de démarrage, créons une instance Chatkit.
Pour créer votre propre instance Chatkit, dirigez-vous vers le tableau de bord et appuyez sur Créer un nouveau :

Donnez à votre instance n'importe quel nom (j'ai appelé le mien "React Chat Tutorial") puis prenez note de votre localisateur d'instance et de votre clé secrète dans l'onglet Keys . Nous en aurons besoin tous les deux dans la section suivante.
Alors que la plupart des interactions se produiront sur le client, Chatkit a également besoin d'un homologue de serveur pour créer et gérer les utilisateurs en toute sécurité:

Nous n'authentifierons pas les utilisateurs dans ce tutoriel, mais nous devrons toujours définir une route qui, une fois appelée, crée un utilisateur de Chatkit.
Commencez par installer @pusher/chatkit-server :
npm install --save @pusher/chatkit-server
Puis mettez à jour ./server.js :
const express = require('express')
const bodyParser = require('body-parser')
const cors = require('cors')
+ const Chatkit = require('@pusher/chatkit-server')
const app = express()
+ const chatkit = new Chatkit.default({
+ instanceLocator: 'YOUR INSTANCE LOCATOR',
+ key: 'YOUR KEY',
+ })
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.use(cors())
+ app.post('/users', (req, res) => {
+ const { username } = req.body
+ chatkit
+ .createUser({
+ id: username,
+ name: username
+ })
+ .then(() => res.sendStatus(201))
+ .catch(error => {
+ if (error.error === 'services/chatkit/user_already_exists') {
+ res.sendStatus(200)
+ } else {
+ res.status(error.status).json(error)
+ }
+ })
+ })
+ app.post('/authenticate', (req, res) => {
+ const authData = chatkit.authenticate({ userId: req.query.user_id })
+ res.status(authData.status).send(authData.body)
+ })
const PORT = 3001
app.listen(PORT, err => {
if (err) {
console.error(err)
} else {
console.log(`Running on port ${PORT}`)
}
})N'oubliez pas de remplacer "votre localisateur d'instance" et "votre clé" par vos propres valeurs respectives.
Il y a beaucoup à déballer ici, à partir du haut:
Chatkit à partir de @pusher/chatkit-serverchatkit en utilisant le localisateur d'instance et la clé que nous avons noté à l'étape précédente/users , nous prenons un username et créons un utilisateur de Chatkit via notre instance chatkit/authenticate pour l'authentifier. Le serveur doit répondre avec un jeton (renvoyé par chatkit.authenticate ) si la demande est valide. Dans notre cas, nous - naïvement - supposerons que tout le monde est ce qu'ils disent être, et retourner un jeton de chatkit.authenticate quoi qu'il arrive.Boom?! C'est tout ce que nous devons faire sur le serveur. Passons au client ...
Lorsque quelqu'un charge l'application, nous voulons leur demander qui il est.
Une fois qu'ils ont appuyé sur Soumettre , nous enverrons leur nom d'utilisateur au serveur (à la route /users que nous venons de définir) et créerons un utilisateur de Chatkit si l'on n'existe pas.
Pour collecter le nom de l'utilisateur, créez un composant appelé UsernameForm.js dans ./src/components/ :
+ import React, { Component } from 'react'
+ class UsernameForm extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ username: '',
+ }
+ this.onSubmit = this.onSubmit.bind(this)
+ this.onChange = this.onChange.bind(this)
+ }
+ onSubmit(e) {
+ e.preventDefault()
+ this.props.onSubmit(this.state.username)
+ }
+ onChange(e) {
+ this.setState({ username: e.target.value })
+ }
+
+ render() {
+ return (
+ <div>
+ <div>
+ <h2>What is your username?</h2>
+ <form onSubmit={this.onSubmit}>
+ <input
+ type="text"
+ placeholder="Your full name"
+ onChange={this.onChange}
+ />
+ <input type="submit" />
+ </form>
+ </div>
+ </div>
+ )
+ }
+ }
+
+ export default UsernameForm Puis mettez à jour App.js :
import React, { Component } from 'react'
+ import UsernameForm from './components/UsernameForm'
class App extends Component {
+ constructor() {
+ super()
+ this.state = {
+ currentUsername: '',
+ }
+ this.onUsernameSubmitted = this.onUsernameSubmitted.bind(this)
+ }
+ onUsernameSubmitted(username) {
+ fetch('http://localhost:3001/users', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({ username }),
+ })
+ .then(response => {
+ this.setState({
+ currentUsername: username
+ })
+ })
+ .catch(error => console.error('error', error))
+ }
render() {
- return <h1>Chatly</h1>
+ return <UsernameForm onSubmit={this.onUsernameSubmitted} />
}
}
export default App Exécutez l'application à l'aide de npm start et vous verrez que l'écran est rendu:

À partir du haut d' App.js :
UsernameForm . Il vous semble probablement familier car il utilise un modèle de réaction commun appelé composants contrôlés. Vous pouvez en savoir plus sur les formulaires React icirender , nous rendons le UsernameForm et connectons le gestionnaire d'événements onUsernameSubmittedonUsernameSubmitted est appelé, nous envoyons une demande de message à la route /users que nous venons de définir. Si la demande est réussie, nous mettons à jour this.state.currentUsername afin que nous puissions le référencer plus tard; Sinon, nous console.error l'erreur Pour le moment, nous rendons le UsernameForm et il occupe tout l'écran (voir la capture d'écran ci-dessus).
Une fois le nom d'utilisateur soumis, nous voulons passer à un autre écran - à savoir l'écran de chat.
Pour ce faire, nous devons d'abord créer un composant ChatScreen.js dans ./src :
+ import React, { Component } from 'react'
+
+ class ChatScreen extends Component {
+ render() {
+ return (
+ <div>
+ <h1>Chat</h1>
+ </div>
+ )
+ }
+ }
+
+ export default ChatScreen Puis mettez à jour App.js :
import React, { Component } from 'react'
import UsernameForm from './components/UsernameForm'
+ import ChatScreen from './ChatScreen'
class App extends Component {
constructor() {
super()
this.state = {
currentUsername: '',
+ currentScreen: 'WhatIsYourUsernameScreen'
}
this.onUsernameSubmitted = this.onUsernameSubmitted.bind(this)
}
onUsernameSubmitted(username) {
fetch('http://localhost:3001/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ username }),
})
.then(response => {
this.setState({
currentUsername: username,
+ currentScreen: 'ChatScreen'
})
})
.catch(error => console.error('error', error))
}
render() {
+ if (this.state.currentScreen === 'WhatIsYourUsernameScreen') {
return <UsernameForm onSubmit={this.onUsernameSubmitted} />
+ }
+ if (this.state.currentScreen === 'ChatScreen') {
+ return <ChatScreen currentUsername={this.state.currentUsername} />
+ }
}
}
export default App Plutôt que d'utiliser un routeur, nous rendons conditionnellement l'écran en fonction de this.state.currentScreen .
Plus tôt, nous avons installé @pusher/chatkit-server . Maintenant, nous sommes également dans le client, vous devrez également installer @pusher/chatkit-client :
npm install --save @pusher/chatkit-client
Ensuite, mettez à jour ChatScreen.js :
import React, { Component } from 'react'
+ import Chatkit from '@pusher/chatkit-client'
class ChatScreen extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ currentUser: {}
+ }
+ }
+ componentDidMount () {
+ const chatManager = new Chatkit.ChatManager({
+ instanceLocator: 'YOUR INSTANCE LOCATOR',
+ userId: this.props.currentUsername,
+ tokenProvider: new Chatkit.TokenProvider({
+ url: 'http://localhost:3001/authenticate',
+ }),
+ })
+
+ chatManager
+ .connect()
+ .then(currentUser => {
+ this.setState({ currentUser })
+ })
+ .catch(error => console.error('error', error))
+ }
render() {
return (
<div>
<h1>Chat</h1>
</div>
)
}
}
export default ChatScreenN'oubliez pas de remplacer "votre localisateur d'instance" par le vôtre que vous avez noté plus tôt.
Encore une fois, à partir du haut:
ChatkitChatManager avec notre instanceLocator , userId (à partir de this.props.currentUsername ) et un TokenProvider personnalisé. Le TokenProvider pointe vers la route /authenticate que nous avons définie plus tôtChatManager a été initialisé, nous pouvons appeler connect . connect se produit de manière asynchrone et une Promise est retournée. Si vous avez suivi ces étapes exactement, vous vous connectez. Cela étant dit, faites attention à toute console.error Error au cas où vous auriez manqué quelque chose Lorsque vous utilisez Chatkit, tous les messages sont envoyés dans une salle de chatkit.
Les chambres peuvent être créées par programme (sur le serveur ou le client à l'aide createRoom ) ou dans l'inspecteur du tableau de bord.
Créer des chambres à partir de l'inspecteur n'est pas vraiment une bonne pratique (elle est principalement destinée aux tests) mais aux fins de cette procédure pas à pas, nous le ferons quand même.
Dans le tableau de bord, dirigez-vous vers l'onglet Console , où vous trouverez l'inspecteur et créez un utilisateur avec n'importe quel nom. J'appellerai le mien "admin".
Ensuite, créez une pièce appelée "Général":

Il est vraiment important de noter l' identifiant unique de la pièce mis en évidence ci-dessus.
Cette étape marque un point important dans la procédure pas à pas.
Maintenant, nous avons notre passe-partout en place, nous pouvons rapidement commencer à créer des fonctionnalités de chat.
À l'avenir, nous décomposons chaque fonctionnalité en composants indépendants (réutilisables, si vous le souhaitez!) React:

Nous allons créer chaque composant au fur et à mesure, mais pour rendre le tutoriel un peu plus facile à suivre, définissons la disposition de l'interface utilisateur de base maintenant:
import React, { Component } from 'react'
import Chatkit from '@pusher/chatkit-client'
class ChatScreen extends Component {
constructor(props) {
super(props)
this.state = {
currentUser: {}
}
}
componentDidMount () {
const chatManager = new Chatkit.ChatManager({
instanceLocator: 'YOUR INSTANCE LOCATOR',
userId: this.props.currentUsername,
tokenProvider: new Chatkit.TokenProvider({
url: 'http://localhost:3001/authenticate',
}),
})
chatManager
.connect()
.then(currentUser => {
this.setState({ currentUser })
})
.catch(error => console.error('error', error))
}
render() {
- return (
- <div>
- <h1>Chat</h1>
- </div>
- )
+ const styles = {
+ container: {
+ height: '100vh',
+ display: 'flex',
+ flexDirection: 'column',
+ },
+ chatContainer: {
+ display: 'flex',
+ flex: 1,
+ },
+ whosOnlineListContainer: {
+ width: '300px',
+ flex: 'none',
+ padding: 20,
+ backgroundColor: '#2c303b',
+ color: 'white',
+ },
+ chatListContainer: {
+ padding: 20,
+ width: '85%',
+ display: 'flex',
+ flexDirection: 'column',
+ },
+ }
+ return (
+ <div style={styles.container}>
+ <div style={styles.chatContainer}>
+ <aside style={styles.whosOnlineListContainer}>
+ <h2>Who's online PLACEHOLDER</h2>
+ </aside>
+ <section style={styles.chatListContainer}>
+ <h2>Chat PLACEHOLDER</h2>
+ </section>
+ </div>
+ </div>
+ )
}
}
export default ChatScreenSi vous exécutez l'application maintenant, vous verrez la mise en page de base se dérouler:

Génial!
Je suis vraiment excité de vous montrer ça!
Maintenant, nous avons une connexion Chatkit , la construction des fonctionnalités de chat devient aussi simple que de connecter les événements Chatkit aux composants de l'interface utilisateur. Ici, laissez-moi vous montrer.
Tout d'abord, créez un composant MessageList.js sans état dans ./src/components :
+ import React, { Component } from 'react'
+
+ class MessagesList extends Component {
+ render() {
+ const styles = {
+ container: {
+ overflowY: 'scroll',
+ flex: 1,
+ },
+ ul: {
+ listStyle: 'none',
+ },
+ li: {
+ marginTop: 13,
+ marginBottom: 13,
+ },
+ senderUsername: {
+ fontWeight: 'bold',
+ },
+ message: { fontSize: 15 },
+ }
+ return (
+ <div
+ style={{
+ ...this.props.style,
+ ...styles.container,
+ }}
+ >
+ <ul style={styles.ul}>
+ {this.props.messages.map((message, index) => (
+ <li key={index} style={styles.li}>
+ <div>
+ <span style={styles.senderUsername}>{message.senderId}</span>{' '}
+ </div>
+ <p style={styles.message}>{message.text}</p>
+ </li>
+ ))}
+ </ul>
+ </div>
+ )
+ }
+ }
+
+ export default MessagesList Ensuite, mettez à jour ChatScreen.js :
import React, { Component } from 'react'
import Chatkit from '@pusher/chatkit-client'
+ import MessageList from './components/MessageList'
class ChatScreen extends Component {
constructor(props) {
super(props)
this.state = {
currentUser: {},
+ currentRoom: {},
+ messages: []
}
}
componentDidMount () {
const chatManager = new Chatkit.ChatManager({
instanceLocator: 'YOUR INSTANCE LOCATOR',
userId: this.props.currentUsername,
tokenProvider: new Chatkit.TokenProvider({
url: 'http://localhost:3001/authenticate',
}),
})
chatManager
.connect()
.then(currentUser => {
this.setState({ currentUser })
+ return currentUser.subscribeToRoom({
+ roomId: "YOUR ROOM ID",
+ messageLimit: 100,
+ hooks: {
+ onMessage: message => {
+ this.setState({
+ messages: [...this.state.messages, message],
+ })
+ },
+ },
+ })
+ })
+ .then(currentRoom => {
+ this.setState({ currentRoom })
+ })
.catch(error => console.error('error', error))
}
render() {
const styles = {
...
}
return (
<div style={styles.container}>
<div style={styles.chatContainer}>
<aside style={styles.whosOnlineListContainer}>
<h2>Who's online PLACEHOLDER</h2>
</aside>
<section style={styles.chatListContainer}>
- <h2>Chat PLACEHOLDER</h2>
+ <MessageList
+ messages={this.state.messages}
+ style={styles.chatList}
+ />
</section>
</div>
</div>
)
}
}
export default ChatScreenN'oubliez pas de remplacer votre identifiant de chambre par votre propre identifiant de chambre que vous avez noté plus tôt.
Décomposons-le:
currentUser qui représente l'utilisateur connecté actuelcurrentUsersubscribeToRoom sur currentUser ( currentUser.subscribeToRoom )subscribeToRoom prend un gestionnaire d'événements appelé onMessage qui est appelé en temps réel à chaque fois qu'un nouveau message arrivemessageLimit à 100 , onMessage est également appelé rétroactivement pour jusqu'à 100 messages les plus récents. En pratique, cela signifie que si vous actualisez la page, vous verrez jusqu'à 100 des messages de chat les plus récentsNous sommes sur un rouleau!
Ensuite, permettez aux utilisateurs d'envoyer des messages en créant d'abord un composant SendMessageForm.js dans ./src/components :
+ import React, { Component } from 'react'
+
+ class SendMessageForm extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ text: '',
+ }
+ this.onSubmit = this.onSubmit.bind(this)
+ this.onChange = this.onChange.bind(this)
+ }
+
+ onSubmit(e) {
+ e.preventDefault()
+ this.props.onSubmit(this.state.text)
+ this.setState({ text: '' })
+ }
+
+ onChange(e) {
+ this.setState({ text: e.target.value })
+ if (this.props.onChange) {
+ this.props.onChange()
+ }
+ }
+
+ render() {
+ const styles = {
+ container: {
+ padding: 20,
+ borderTop: '1px #4C758F solid',
+ marginBottom: 20,
+ },
+ form: {
+ display: 'flex',
+ },
+ input: {
+ color: 'inherit',
+ background: 'none',
+ outline: 'none',
+ border: 'none',
+ flex: 1,
+ fontSize: 16,
+ },
+ }
+ return (
+ <div style={styles.container}>
+ <div>
+ <form onSubmit={this.onSubmit} style={styles.form}>
+ <input
+ type="text"
+ placeholder="Type a message here then hit ENTER"
+ onChange={this.onChange}
+ value={this.state.text}
+ style={styles.input}
+ />
+ </form>
+ </div>
+ </div>
+ )
+ }
+ }
+
+ export default SendMessageForm Ensuite - vous l'avez deviné - Mettez à jour ChatScreen.js :
import React, { Component } from 'react'
import Chatkit from '@pusher/chatkit-client'
import MessageList from './components/MessageList'
+ import SendMessageForm from './components/SendMessageForm'
class ChatScreen extends Component {
constructor(props) {
super(props)
this.state = {
currentUser: {},
currentRoom: {},
messages: []
}
+ this.sendMessage = this.sendMessage.bind(this)
}
+ sendMessage(text) {
+ this.state.currentUser.sendMessage({
+ text,
+ roomId: this.state.currentRoom.id,
+ })
+ }
componentDidMount () {
const chatManager = new Chatkit.ChatManager({
instanceLocator: 'YOUR INSTANCE LOCATOR',
userId: this.props.currentUsername,
tokenProvider: new Chatkit.TokenProvider({
url: 'http://localhost:3001/authenticate',
}),
})
chatManager
.connect()
.then(currentUser => {
this.setState({ currentUser })
return currentUser.subscribeToRoom({
roomId: YOUR ROOM ID,
messageLimit: 100,
hooks: {
onMessage: message => {
this.setState({
messages: [...this.state.messages, message],
})
},
},
})
})
.then(currentRoom => {
this.setState({ currentRoom })
})
.catch(error => console.error('error', error))
}
render() {
const styles = {
...
}
return (
<div style={styles.container}>
<div style={styles.chatContainer}>
<aside style={styles.whosOnlineListContainer}>
<h2>Who's online PLACEHOLDER</h2>
</aside>
<section style={styles.chatListContainer}>
<MessageList
messages={this.state.messages}
style={styles.chatList}
/>
+ <SendMessageForm onSubmit={this.sendMessage} />
</section>
</div>
</div>
)
}
}
export default ChatScreen Le composant SendMessageForm est essentiellement le même que le composant WhatIsYourUsernameForm que nous avons défini précédemment.
Lorsque le SendMessageForm est soumis, nous accédons this.state.currentUser et appelons sendMessage (rappelez-vous, la plupart des interactions se produisent sur currentUser )
Vous pouvez probablement voir un modèle émerger ...
ChatScreen est un composant conteneur qui gère notre état d'application et rend l'interface utilisateur à l'aide de composants sans état sans état. La plupart de notre code consiste à connecter les événements Chatkit et à leurs données associées pour réagir les composants de l'interface utilisateur.
Si vous avez déjà tenté de mettre en œuvre vos propres indicateurs de frappe, vous saurez que cela peut être délicat. En général, plus de fonctionnalités en temps réel signifie plus de données et plus de connexions à gérer.
Avec Chatkit, vous pouvez ajouter des indicateurs de frappe avec peu d'effort.
Commencez par créer un composant TypingIndicator.js dans ./src/components :
+ import React, { Component } from 'react'
+
+ class TypingIndicator extends Component {
+ render() {
+ if (this.props.usersWhoAreTyping.length > 0) {
+ return (
+ <div>
+ {`${this.props.usersWhoAreTyping
+ .slice(0, 2)
+ .join(' and ')} is typing`}
+ </div>
+ )
+ }
+ return <div />
+ }
+ }
+
+ export default TypingIndicator Ensuite, mettez à jour ChatScreen.js :
import React, { Component } from 'react'
import Chatkit from '@pusher/chatkit-client'
import MessageList from './components/MessageList'
import SendMessageForm from './components/SendMessageForm'
+ import TypingIndicator from './components/TypingIndicator'
class ChatScreen extends Component {
constructor(props) {
super(props)
this.state = {
currentUser: {},
currentRoom: {},
messages: [],
+ usersWhoAreTyping: [],
}
this.sendMessage = this.sendMessage.bind(this)
+ this.sendTypingEvent = this.sendTypingEvent.bind(this)
}
+ sendTypingEvent() {
+ this.state.currentUser
+ .isTypingIn({ roomId: this.state.currentRoom.id })
+ .catch(error => console.error('error', error))
+ }
sendMessage(text) {
this.state.currentUser.sendMessage({
text,
roomId: this.state.currentRoom.id,
})
}
componentDidMount() {
const chatManager = new Chatkit.ChatManager({
instanceLocator: 'YOUR INSTANCE LOCATOR',
userId: this.props.currentUsername,
tokenProvider: new Chatkit.TokenProvider({
url: 'http://localhost:3001/authenticate',
}),
})
chatManager
.connect()
.then(currentUser => {
this.setState({ currentUser })
return currentUser.subscribeToRoom({
roomId: YOUR ROOM ID,
messageLimit: 100,
hooks: {
onMessage: message => {
this.setState({
messages: [...this.state.messages, message],
})
},
+ onUserStartedTyping: user => {
+ this.setState({
+ usersWhoAreTyping: [...this.state.usersWhoAreTyping, user.name],
+ })
+ },
+ onUserStoppedTyping: user => {
+ this.setState({
+ usersWhoAreTyping: this.state.usersWhoAreTyping.filter(
+ username => username !== user.name
+ ),
+ })
+ },
},
})
})
.then(currentRoom => {
this.setState({ currentRoom })
})
.catch(error => console.error('error', error))
}
render() {
const styles = {
...
}
return (
<div style={styles.container}>>
<div style={styles.chatContainer}>
<aside style={styles.whosOnlineListContainer}>
<h2>Who's online PLACEHOLDER</h2>
</aside>
<section style={styles.chatListContainer}>
<MessageList
messages={this.state.messages}
style={styles.chatList}
/>
+ <TypingIndicator usersWhoAreTyping={this.state.usersWhoAreTyping} />
<SendMessageForm
onSubmit={this.sendMessage}
+ onChange={this.sendTypingEvent}
/>
</section>
</div>
</div>
)
}
}
export default ChatScreenLorsque vous utilisez Chatkit, les indicateurs de dactylographie se résument à deux actions fondamentales:
currentUser.userIsTyping lorsque l'utilisateur actuel commence à taper; alors,userStartedTyping et userStoppedTypingEt c'est à peu près tout.
"Mais Alex, qu'en est-il lorsque l'utilisateur cesse de taper?"
C'est une très bonne question.
Chatkit est intelligent comme ça. Si le service ne reçoit pas d'événement userIsTyping après quelques secondes, il suppose que currentUser a cessé de taper. Par conséquent, il n'est pas nécessaire de soulever manuellement un événement lorsque quelqu'un cesse de taper. Assez lisse, non?
Pouvez-vous ressentir l'élan? Presque fait maintenant?
Pour terminer l'application de chat, utilisons la fonctionnalité "Who's Online" de Chatkit pour rendre une liste d'utilisateurs et leur statut en ligne en temps réel.
Commencez par créer un composant WhosOnlineList.js dans /src/components :
+ import React, { Component } from 'react'
+
+ class WhosOnlineList extends Component {
+ renderUsers() {
+ return (
+ <ul>
+ {this.props.users.map((user, index) => {
+ if (user.id === this.props.currentUser.id) {
+ return (
+ <WhosOnlineListItem key={index} presenceState="online">
+ {user.name} (You)
+ </WhosOnlineListItem>
+ )
+ }
+ return (
+ <WhosOnlineListItem key={index} presenceState={user.presence.state}>
+ {user.name}
+ </WhosOnlineListItem>
+ )
+ })}
+ </ul>
+ )
+ }
+
+ render() {
+ if (this.props.users) {
+ return this.renderUsers()
+ } else {
+ return <p>Loading...</p>
+ }
+ }
+ }
+
+ class WhosOnlineListItem extends Component {
+ render() {
+ const styles = {
+ li: {
+ display: 'flex',
+ alignItems: 'center',
+ marginTop: 5,
+ marginBottom: 5,
+ paddingTop: 2,
+ paddingBottom: 2,
+ },
+ div: {
+ borderRadius: '50%',
+ width: 11,
+ height: 11,
+ marginRight: 10,
+ },
+ }
+ return (
+ <li style={styles.li}>
+ <div
+ style={{
+ ...styles.div,
+ backgroundColor:
+ this.props.presenceState === 'online' ? '#539eff' : '#414756',
+ }}
+ />
+ {this.props.children}
+ </li>
+ )
+ }
+ }
+
+ export default WhosOnlineList Alors - pour la dernière fois? - Mettre à jour ChatScreen.js :
import React, { Component } from 'react'
import Chatkit from '@pusher/chatkit-client'
import MessageList from './components/MessageList'
import SendMessageForm from './components/SendMessageForm'
import TypingIndicator from './components/TypingIndicator'
+ import WhosOnlineList from './components/WhosOnlineList'
class ChatScreen extends Component {
constructor(props) {
super(props)
this.state = {
currentUser: {},
currentRoom: {},
messages: [],
usersWhoAreTyping: [],
}
this.sendMessage = this.sendMessage.bind(this)
this.sendTypingEvent = this.sendTypingEvent.bind(this)
}
sendTypingEvent() {
this.state.currentUser
.isTypingIn(this.state.currentRoom.id)
.catch(error => console.error('error', error))
}
sendMessage(text) {
this.state.currentUser.sendMessage({
text,
roomId: this.state.currentRoom.id,
})
}
comonentDidMount() {
const chatManager = new Chatkit.ChatManager({
instanceLocator: 'YOUR INSTANCE LOCATOR',
userId: this.props.currentUsername,
tokenProvider: new Chatkit.TokenProvider({
url: 'http://localhost:3001/authenticate',
}),
})
chatManager
.connect()
.then(currentUser => {
this.setState({ currentUser })
return currentUser.subscribeToRoom({
roomId: YOUR ROOM ID,
messageLimit: 100,
hooks: {
newMessage: message => {
this.setState({
messages: [...this.state.messages, message],
})
},
userStartedTyping: user => {
this.setState({
usersWhoAreTyping: [...this.state.usersWhoAreTyping, user.name],
})
},
userStoppedTyping: user => {
this.setState({
usersWhoAreTyping: this.state.usersWhoAreTyping.filter(
username => username !== user.name
),
})
},
+ onPresenceChange: () => this.forceUpdate(),
},
})
})
.then(currentRoom => {
this.setState({ currentRoom })
})
.catch(error => console.error('error', error))
}
render() {
const styles = {
...
}
return (
<div style={styles.container}>
<header style={styles.header}>
<h2>Chatly</h2>
</header>
<div style={styles.chatContainer}>
<aside style={styles.whosOnlineListContainer}>
- <h2>Who's online PLACEHOLDER</h2>
+ <WhosOnlineList
+ currentUser={this.state.currentUser}
+ users={this.state.currentRoom.users}
+ />
</aside>
<section style={styles.chatListContainer}>
<MessageList
messages={this.state.messages}
style={styles.chatList}
/>
<TypingIndicator usersWhoAreTyping={this.state.usersWhoAreTyping} />
<SendMessageForm
onSubmit={this.sendMessage}
onChange={this.sendTypingEvent}
/>
</section>
</div>
</div>
)
}
}
export default ChatScreen La gestion de l'état de vos utilisateurs à l'état React peut être un peu délicate, nous le gérons donc pour vous dans currentRoom.users .
Au fur et à mesure que les utilisateurs se connectent et se déconnectent, cette propriété est mise à jour dynamiquement. En d'autres termes, currentRoom.users doit toujours refléter l'état actuel de votre application de chat.
Par conséquent, lorsque les utilisateurs se mettent en ligne ou se déconnectent ( onPresenceChange ), ou que les nouveaux utilisateurs se joignent ( onUserAdded ), tout ce que nous avons à faire est d'appeler forceUpdate qui indique à React pour évaluer currentRoom.users et mettre à jour l'interface utilisateur.
Encore une fois, cela se résume vraiment au câblage de quelques données et événements simples pour réagir des composants et c'est tout, les amis!
Dans cette procédure pas à pas, vous avez construit une application de chat complète avec
Parce que nous avons utilisé Chatkit, nous obtenons également des fonctionnalités de bonus gratuitement:
Nous avons écrit une bonne quantité de code, mais rien de tout cela n'était particulièrement compliqué.
Chatkit a une API minimale mais puissante qui gère toutes nos données de chat pour nous. Tout ce que nous avions à faire est de prendre ces données et de les rendre pour l'utilisateur.
Vous voulez continuer à construire? Pourquoi ne pas ajouter une prise en charge des médias riches et lire les reçus? Chatkit prend en charge les deux:
Vous pouvez également être intéressé à consulter notre puissante démo Chatkit Slack (250+ étoiles ️). C'est similaire à l'application que nous venons de construire mais plus complète.
Que allez-vous construire avec Chatkit? Nous serions ravis de voir! Vos commentaires nous guident dans l'amélioration de Chatkit. Faites-nous savoir ce qui vous aide à atteindre vos objectifs, ce qui vous gêne ou ce qui manque.