Neste tutorial, você aprenderá como criar um aplicativo de bate -papo com o React e o ChatKit.
Quando terminarmos, teremos um aplicativo de bate -papo completo com indicadores de digitação , uma lista de "quem está online" e histórico de mensagens :

Se você acha que isso parece muito para enfrentar em um tutorial, normalmente estaria certo!
No entanto, como usaremos o ChatKit, podemos focar mais ou menos exclusivamente no código React front-end enquanto o ChatKit faz o levantamento pesado.
O ChatKit é uma API hospedada que ajuda a criar recursos de bate -papo impressionantes em seus aplicativos com menos código. Recursos como,
Usando nossos SDKs de plataforma cruzada, todos os dados de bate-papo são enviados à nossa API hospedada, onde gerenciamos o estado de bate-papo e os transmitimos para seus clientes:

Você nunca precisará se preocupar com escala ou infraestrutura, cuidamos de tudo para você.
Talvez a melhor maneira de aprender o ChatKit seja começar a construir, então eu recomendo que você acompanhe. Ao longo do caminho, você aprenderá as melhores práticas ao usar o ChatKit com o React.
Este tutorial foi escrito para que você possa acompanhar, passo a passo. Existem 12 etapas no total.
Aqui está um resumo rápido para que você saiba o que esperar:
Tudo bem, vamos codificar!
Em vez de começar do arranhão absoluto, este passo a passo é baseado em um modelo de partida mínimo:

Como você pode ver, o modelo de partida não contém lógica interessante - apenas o Boilerplate precisamos executar um aplicativo React e um servidor de nó simples.
"Servidor? Ninguém mencionou um servidor!"
Se você não está muito familiarizado com o nó, não se preocupe? Após a próxima seção, não precisaremos tocar no servidor.
Para começar, faça o download do modelo de partida e execute 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 o código preenchido, você pode visualizar a filial completed ou executar git checkout complete localmente.)
(Observe também: este tutorial assume o uso do npm , mas os comandos yarn equivalentes também funcionarão.)
Agora você baixou o modelo de partida, vamos criar uma instância do ChatKit.
Para criar sua própria instância do ChatKit, vá para o painel e pressione Crie Novo :

Dê à sua instância qualquer nome (liguei para o meu "React Chat Tutorial"), então tome nota do localizador da instância e da tecla secreta na guia Chaves . Precisamos de ambos na próxima seção.
Embora a maioria das interações aconteça no cliente, o ChatKit também precisa de uma contraparte do servidor para criar e gerenciar usuários com segurança:

Não vamos autenticar os usuários deste tutorial, mas ainda precisaremos definir uma rota que, quando chamada, cria um usuário do ChatKit.
Comece instalando @pusher/chatkit-server :
npm install --save @pusher/chatkit-server
Em seguida, atualize ./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}`)
}
})Lembre -se de substituir "o localizador da sua instância" e "sua chave" pelos seus próprios valores.
Há muito o que descompactar aqui, a partir do topo:
Chatkit de @pusher/chatkit-serverchatkit usando o localizador e a chave da instância que observamos na etapa anterior/users , tomamos um username e criamos um usuário do ChatKit através de nossa instância chatkit/authenticate para autenticá -los. O servidor precisa responder com um token (retornado pelo chatkit.authenticate ) se a solicitação for válida. No nosso caso, nós - ingenuamente - assumiremos que todos são quem eles dizem que são e devolvermos um token do chatkit.authenticate , não importa o quê.Boom?! É tudo o que precisamos fazer no servidor. Vamos para o cliente ...
Quando alguém carrega o aplicativo, queremos perguntar quem eles são.
Depois de enviar o envio , enviaremos o nome de usuário para o servidor (para a rota /users que acabamos de definir) e criarmos um usuário do ChatKit se não existir.
Para coletar o nome do usuário, crie um componente chamado UsernameForm.js em ./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 Em seguida, atualize 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 Execute o aplicativo usando npm start e você verá que a tela é renderizada:

Começando do topo do App.js :
UsernameForm . Provavelmente parece familiar para você porque usa um padrão de reação comum chamado componentes controlados. Você pode ler mais sobre os formulários reactos aquirender , renderizamos o UsernameForm e conectamos o manipulador de eventos onUsernameSubmittedonUsernameSubmitted é chamado, enviamos uma solicitação de postagem para a rota /users que acabamos de definir. Se a solicitação for bem -sucedida, atualizamos this.state.currentUsername . Caso contrário, console.error o erro No momento, renderizamos o UsernameForm e ele ocupa toda a tela (veja a captura de tela acima).
Depois que o nome de usuário for enviado, vamos fazer a transição para uma tela diferente - a saber, a tela de bate -papo.
Para fazer isso, primeiro precisamos criar um componente ChatScreen.js em ./src :
+ import React, { Component } from 'react'
+
+ class ChatScreen extends Component {
+ render() {
+ return (
+ <div>
+ <h1>Chat</h1>
+ </div>
+ )
+ }
+ }
+
+ export default ChatScreen Em seguida, atualize 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 Em vez de usar um roteador, renderizamos condicionalmente a tela com base this.state.currentScreen .
Anteriormente, instalamos @pusher/chatkit-server . Agora estamos na terra do cliente, você também precisará instalar @pusher/chatkit-client :
npm install --save @pusher/chatkit-client
Em seguida, atualize 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 ChatScreenLembre -se de substituir o "Localizador de instância" pelo seu que você observou anteriormente.
Novamente, começando de cima:
ChatkitChatManager com nosso instanceLocator , userId ( this.props.currentUsername ) e um TokenProvider personalizado. A TokenProvider aponta para a rota /authenticate que definimos anteriormenteChatManager for inicializado, podemos ligar para connect . connect acontece de forma assíncrona e uma Promise é devolvida. Se você seguiu exatamente essas etapas, você se conectará. Dito isto, cuidado com qualquer console.error Ao usar o ChatKit, todas as mensagens são enviadas para uma sala de chatkit.
Os quartos podem ser criados programaticamente (no servidor ou cliente usando createRoom ) ou no inspetor do painel.
Criar quartos do inspetor não é realmente uma boa prática (é principalmente destinada a testes), mas para os fins deste passo a passo, faremos isso de qualquer maneira.
No painel, vá para a guia Console , onde você encontrará o inspetor e criará um usuário com qualquer nome. Vou chamar o meu "admin".
Em seguida, crie uma sala chamada "general":

É realmente importante observar o ID da sala exclusivo destacado acima.
Esta etapa marca um ponto significativo no passo a passo.
Agora temos o nosso caldeira no lugar, podemos começar rapidamente a criar recursos de bate -papo.
No futuro, dividiremos cada recurso em componentes independentes (reutilizáveis, se você quiser!), Reaja componentes:

Criaremos cada componente à medida que avançamos, mas para facilitar o seguimento do tutorial, vamos definir o layout básico da interface do usuário agora:
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 ChatScreenSe você executar o aplicativo agora, verá o layout básico:

Incrível!
Estou realmente animado para mostrar isso!
Agora, temos uma conexão Chatkit , a criação de recursos de bate -papo se torna tão simples quanto conectar eventos de chatkit aos componentes da interface do usuário. Aqui, deixe -me mostrar a você.
Primeiro, crie um componente apátrida MessageList.js em ./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 Em seguida, atualize 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 ChatScreenLembre -se de substituir o ID do seu quarto pelo seu próprio ID de quarto que você observou anteriormente.
Vamos quebrá -lo:
currentUser que representa o usuário conectado atualcurrentUsersubscribeToRoom no currentUser ( currentUser.subscribeToRoom )subscribeToRoom leva um manipulador de eventos chamado onMessage , chamado em tempo real, cada vez que uma nova mensagem chegamessageLimit seja 100 , onMessage também é chamado retroativamente para até 100 mensagens mais recentes. Na prática, isso significa que, se você atualizar a página, verá até 100 das mensagens de bate -papo mais recentesEstamos em um rolo!
Em seguida, vamos permitir que os usuários enviem mensagens, criando primeiro um componente SendMessageForm.js em ./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 Então - você adivinhou - atualize 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 O componente SendMessageForm é essencialmente o mesmo que o componente WhatIsYourUsernameForm que definimos anteriormente.
Quando o SendMessageForm é enviado, acessamos this.state.currentUser e ligue para sendMessage (lembre -se, a maioria das interações acontece no currentUser )
Você provavelmente pode ver um padrão emergindo ...
ChatScreen é um componente de contêiner que gerencia nosso estado de aplicação e renderiza a interface do usuário usando componentes de apresentação - normalmente apátrida -. A maior parte do nosso código envolve a conexão de eventos do ChatKit e seus dados associados para reagir componentes da interface do usuário.
Se você já tentou implementar seus próprios indicadores de digitação, saberá que pode ser complicado. Em geral, mais recursos em tempo real significam mais dados e mais conexões para gerenciar.
Com o ChatKit, você pode adicionar indicadores de digitação com pouco esforço.
Comece criando um componente TypingIndicator.js em ./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 Em seguida, atualize 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 ChatScreenAo usar o ChatKit, os indicadores de digitação se resumem a duas ações fundamentais:
currentUser.userIsTyping quando o usuário atual começa a digitar; então,userStartedTyping e userStoppedTypingE é isso.
"Mas Alex, e quando o usuário para de digitar?"
Essa é uma pergunta muito boa.
Chatkit é inteligente assim. Se o serviço não receber um evento userIsTyping após alguns segundos, ele pressupõe que o currentUser parasse de digitar. Portanto, não há necessidade de aumentar manualmente um evento quando alguém para de digitar. Muito liso, certo?
Você pode sentir o momento? Quase feito agora?
Para finalizar o aplicativo de bate-papo, vamos usar o recurso "Who Online" do ChatKit para renderizar uma lista de usuários e seu status on-line em tempo real.
Comece criando um componente WhosOnlineList.js em /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 Então - pela última vez? - Atualize 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 Gerenciar o estado de seus usuários no estado do React pode ser um pouco complicado, por isso gerenciamos isso para você na currentRoom.users .
À medida que os usuários se conectam e se desconectam, essa propriedade é atualizada dinamicamente. Em outras palavras, currentRoom.users deve sempre refazer o estado atual do seu aplicativo de bate -papo.
Portanto, quando os usuários ficam on -line ou ficam offline ( onPresenceChange ), ou novos usuários ingressam ( onUserAdded ), tudo o que precisamos fazer é chamar forceUpdate , que diz ao React para avaliar currentRoom.users e atualizar a interface do usuário.
Novamente, tudo se resume a conectar alguns dados e eventos simples para reagir componentes e isso é tudo, pessoal!
Neste passo a passo, você construiu um aplicativo de bate -papo completo com
Como usamos o ChatKit, também temos alguns recursos de bônus gratuitamente:
Escrevemos uma quantidade razoável de código, mas nada disso foi particularmente complicado.
O ChatKit possui uma API mínima, mas poderosa, que gerencia todos os nossos dados de bate -papo para nós. Tudo o que tivemos que fazer é pegar esses dados e renderizá -los para o usuário.
Quer continuar construindo? Por que não adicionar suporte de mídia rico e recibos de leitura? O ChatKit suporta os dois:
Você também pode estar interessado em verificar nossa poderosa demonstração do Chatkit Slack (mais de 250 estrelas ️). É semelhante ao aplicativo que acabamos de construir, mas mais completo.
O que você vai construir com o ChatKit? Adoraríamos ver! Seus comentários nos guia para melhorar o ChatKit. Deixe -nos saber o que ajuda você a alcançar seus objetivos, o que está ficando no seu caminho ou o que está faltando.