En este tutorial, aprenderá cómo crear una aplicación de chat con React y Chatkit.
Cuando hayamos terminado, tendremos una solicitud de chat completa con indicadores de escritura , una lista de "quién está en línea" e historial de mensajes :

Si crees que esto parece mucho abordar en un tutorial, ¡normalmente tendrías razón!
Sin embargo, debido a que usaremos ChatKit, podemos centrarnos más o menos exclusivamente en el código React front-end mientras ChatKit hace el trabajo pesado.
Chatkit es una API alojada que lo ayuda a generar impresionantes características de chat en sus aplicaciones con menos código. Características como,
Utilizando nuestros SDK multiplataforma, todos los datos de chat se envían a nuestra API alojada donde administramos el estado de chat y los transmitimos a sus clientes:

Nunca tendrá que preocuparse por la escala o la infraestructura, nos cuidamos todo por usted.
Quizás la mejor manera de aprender Chatkit es comenzar a construir, por lo que le recomiendo que siga. En el camino, aprenderá las mejores prácticas cuando use Chatkit con React.
Este tutorial ha sido escrito para que pueda seguirlo, paso a paso. Hay 12 pasos en total.
Aquí hay un resumen rápido para que sepa qué esperar:
Muy bien, ¡codifiquemos!
En lugar de comenzar desde el scratch absoluto, este tutorial se basa en una plantilla de inicio mínima:

Como puede ver, la plantilla de inicio no contiene ninguna lógica interesante; solo la Boilerplate necesitamos ejecutar una aplicación React y un servidor de nodo simple.
"¿Servidor? ¡Nadie mencionó un servidor!"
Si no estás demasiado familiarizado con el nodo, ¿no te preocupes? Después de la siguiente sección, no tendremos que tocar el servidor.
Para comenzar, descargue la plantilla de inicio y luego ejecute npm install :
git clone https://github.com/pusher/build-a-slack-clone-with-react-and-pusher-chatkit chatkit-tutorial
cd chatkit-tutorial
npm install
(Nota: Para ver el código completado, puede ver la rama completed o ejecutar git checkout complete localmente).
(Tenga en cuenta también: este tutorial supone el uso de npm , pero los comandos yarn equivalentes también funcionarán).
Ahora ha descargado la plantilla de inicio, creemos una instancia de chatkit.
Para crear su propia instancia de chatkit, diríjase al tablero y presione Crear nuevo :

Dale a tu instancia cualquier nombre (llamé al mío "Tutorial de chat React") y luego tome nota de su localizador de instancia y clave secreta en la pestaña Cayos . Los necesitaremos ambos en la siguiente sección.
Si bien la mayoría de las interacciones ocurrirán en el cliente, ChatKit también necesita una contraparte del servidor para crear y administrar a los usuarios de forma segura:

No autenticaremos a los usuarios en este tutorial, pero aún así tendremos que definir una ruta que, cuando se llama, crea un usuario de chatkit.
Comience instalando @pusher/chatkit-server :
npm install --save @pusher/chatkit-server
Luego actualice ./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}`)
}
})Recuerde reemplazar "su localización de instancias" y "su clave" con sus propios valores respectivos.
Hay mucho que desempacar aquí, comenzando desde arriba:
Chatkit de @pusher/chatkit-serverchatkit usando el localizador de instancias y la clave que notamos en el paso anterior/users , tomamos un username y creamos un usuario de chatkit a través de nuestra instancia chatkit/authenticate para autenticarlos. El servidor debe responder con un token (devuelto por chatkit.authenticate ) si la solicitud es válida. En nuestro caso,, ingenuamente, asumiremos que todos son quienes dicen que son y devolveremos un token de chatkit.authenticate Autorizar sin importar qué.BOOM? Eso es todo lo que necesitamos hacer en el servidor. Pasemos al cliente ...
Cuando alguien carga la aplicación, queremos preguntarles quiénes son.
Una vez que presionen enviar , enviaremos su nombre de usuario al servidor (a la ruta /users que acabamos de definir) y crearemos un usuario de chatkit si no existe.
Para recopilar el nombre del usuario, cree un componente llamado UsernameForm.js en ./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 Luego actualice 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 Ejecute la aplicación con npm start y verá que la pantalla está representada:

Comenzando desde la parte superior de App.js :
UsernameForm . Probablemente le parezca familiar porque utiliza un patrón React común llamado componentes controlados. Puedes leer más sobre los formularios react aquírender , renderizamos el UsernameForm y conectamos el controlador de eventos onUsernameSubmittedonUsernameSubmitted , enviamos una solicitud de publicación a la ruta /users que acabamos de definir. Si la solicitud es exitosa, actualizamos this.state.currentUsername para que podamos hacer referencia a ella más tarde; de lo contrario, console.error Error el error Por el momento, representamos el UsernameForm y ocupa toda la pantalla (vea la captura de pantalla anterior).
Una vez que se haya enviado el nombre de usuario, queremos hacer la transición a una pantalla diferente, a saber, la pantalla de chat.
Para hacer eso, primero necesitamos crear un componente ChatScreen.js en ./src :
+ import React, { Component } from 'react'
+
+ class ChatScreen extends Component {
+ render() {
+ return (
+ <div>
+ <h1>Chat</h1>
+ </div>
+ )
+ }
+ }
+
+ export default ChatScreen Luego actualice 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 En lugar de usar un enrutador, representamos condicionalmente la pantalla en función de this.state.currentScreen .
Anteriormente, instalamos @pusher/chatkit-server . Ahora estamos en tierra de cliente, también deberá instalar @pusher/chatkit-client :
npm install --save @pusher/chatkit-client
Luego actualice 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 ChatScreenRecuerde reemplazar "su localización de instancias" con el suyo que notara anteriormente.
De nuevo, comenzando desde arriba:
ChatkitChatManager con nuestro instanceLocator , userId (de this.props.currentUsername ) y un TokenProvider personalizado. TokenProvider señala la ruta /authenticate que definimos anteriormenteChatManager ha sido inicializado, podemos llamar connect . connect ocurre de manera asincrónica y se devuelve una Promise . Si ha seguido estos pasos exactamente, se conectará. Dicho esto, ten cuidado con cualquier console.error Al usar chatkit, todos los mensajes se envían a una sala de chatkit.
Las habitaciones se pueden crear programáticamente (en el servidor o el cliente usando createRoom ) o en el inspector de tablero.
Crear habitaciones del inspector no es realmente una buena práctica (está destinada principalmente a las pruebas), pero para este tutorial, lo haremos de todos modos.
En el tablero, diríjase a la pestaña de la consola , donde encontrará al inspector y creará un usuario con cualquier nombre. Llamaré al mío "administrador".
Luego, cree una habitación llamada "General":

Es realmente importante tener en cuenta la ID de habitación única resaltada anteriormente.
Este paso marca un punto significativo en el tutorial.
Ahora tenemos nuestra horizonte en su lugar, podemos comenzar rápidamente a construir funciones de chat.
En el futuro, desglosaremos cada característica en componentes reaccionarios independientes (¡reutilizables, si lo desea!)

Crearemos cada componente a medida que avanzamos, pero para que el tutorial sea un poco más fácil de seguir, establezcamos el diseño de interfaz de usuario de componente básico ahora:
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 ejecuta la aplicación ahora, verá que el diseño básico tiene lugar:

¡Impresionante!
¡Estoy realmente emocionado de mostrarte esto!
Ahora tenemos una conexión Chatkit , construir características de chat se vuelve tan simple como conectar eventos de chatkit a los componentes de la interfaz de usuario. Aquí, déjame mostrarte.
Primero, cree un componente MessageList.js en ./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 Luego actualice 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 ChatScreenRecuerde reemplazar su identificación de habitación con su propia identificación de habitación que notó anteriormente.
Vamos a desglosarlo:
currentUser que represente al usuario conectado actualcurrentUsersubscribeToRoom en currentUser ( currentUser.subscribeToRoom )subscribeToRoom toma un controlador de eventos llamado onMessage que se llama en tiempo real cada vez que llega un nuevo mensajemessageLimit es 100 , onMessage también se llama retroactivamente para hasta 100 mensajes más recientes. En la práctica, esto significa que si actualiza la página, verá hasta 100 de los mensajes de chat más recientes.¡Estamos en racha!
A continuación, permitamos a los usuarios enviar mensajes creando primero un componente SendMessageForm.js en ./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 Entonces, lo has adivinado - Actualizar 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 El componente SendMessageForm es esencialmente el mismo que el componente WhatIsYourUsernameForm que definimos anteriormente.
Cuando se envía SendMessageForm , accedemos a this.state.currentUser y llame sendMessage (recuerde, la mayoría de las interacciones ocurren en currentUser )
Probablemente puedas ver un patrón emergente ...
ChatScreen es un componente de contenedores que administra nuestro estado de aplicación y hace que la interfaz de usuario use componentes presentes, normalmente apátridas,. La mayor parte de nuestro código implica conectar eventos de chatkit y sus datos asociados para reaccionar los componentes de la interfaz de usuario.
Si alguna vez ha intentado implementar sus propios indicadores de escritura, sabrá que puede ser complicado. En general, más características en tiempo real significa más datos y más conexiones para administrar.
Con Chatkit, puede agregar indicadores de escritura con poco esfuerzo.
Comience creando un componente TypingIndicator.js en ./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 Luego actualice 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 ChatScreenAl usar chatkit, los indicadores de escritura se reducen a dos acciones fundamentales:
currentUser.userIsTyping cuando el usuario actual comienza a escribir; entonces,userStartedTyping y userStoppedTypingY eso es todo.
"Pero Alex, ¿qué pasa cuando el usuario deja de escribir?"
Esa es una muy buena pregunta.
Chatkit es inteligente así. Si el servicio no recibe un evento userIsTyping después de unos segundos, supone que currentUser ha dejado de escribir. Por lo tanto, no hay necesidad de plantear manualmente un evento cuando alguien deja de escribir. Bastante resbaladizo, ¿verdad?
¿Puedes sentir el impulso? ¿Casi hecho ahora?
Para terminar la aplicación de chat, usemos la función "Who's Online" de Chatkit para representar una lista de usuarios y su estado en línea en tiempo real.
Comience creando un componente WhosOnlineList.js en /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 Entonces, ¿por última vez? - Actualizar 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 Administrar el estado de sus usuarios en React State puede ser un poco complicado, por lo que lo administramos para usted en currentRoom.users .
A medida que los usuarios se conectan y desconectan, esta propiedad se actualiza dinámicamente. En otras palabras, currentRoom.users siempre deben reflejar el estado actual de su aplicación de chat.
Por lo tanto, cuando los usuarios se conectan o desconectan ( onPresenceChange ), o los nuevos usuarios se unen ( onUserAdded ), todo lo que tenemos que hacer es llamar forceUpdate , lo que le dice a React que evalúe currentRoom.users y actualizar la interfaz de usuario.
Nuevamente, realmente se reduce a cablear algunos datos y eventos simples para reaccionar componentes y eso es todo, ¡amigos!
En este tutorial, creó una solicitud de chat completa con
Debido a que usamos chatkit, también obtenemos algunas características de bonificación de forma gratuita:
Escribimos una buena cantidad de código, pero nada de eso fue particularmente complicado.
Chatkit tiene una API mínima pero poderosa que administra todos nuestros datos de chat para nosotros. Todo lo que tuvimos que hacer era tomar esos datos y representarlo para el usuario.
¿Quieres seguir construyendo? ¿Por qué no agregar soporte de medios rico y leer recibos? Chatkit admite ambos:
También puede estar interesado en ver nuestra poderosa demostración de chatkit slack (más de 250 estrellas ️). Es similar a la aplicación que acabamos de construir pero más completa.
¿Qué construirás con chatkit? ¡Nos encantaría ver! Sus comentarios nos guían para mejorar el chatkit. Háganos saber qué lo ayuda a alcanzar sus objetivos, qué se interpone en su camino o qué falta.