В этом уроке вы узнаете, как создать приложение чата с помощью React и Chatkit.
Когда мы закончим, у нас будет приложение в чате с указанием индикаторов печати , списком «Кто онлайн» и история сообщений :

Если вы думаете, что это звучит как многое, чтобы заняться одним учебником, вы обычно будете правы!
Однако, поскольку мы будем использовать Чаткит, мы можем более или менее сосредоточиться исключительно на коде реагирования фронта, в то время как Чаткит делает тяжелую работу.
Чаткит - это размещенный API, который помогает вам встроить впечатляющие функции чата в ваши приложения с меньшим кодом. Такие функции, как,
Используя наши кроссплатформенные SDK, все данные чата отправляются в наш хостированный API, где мы управляем состоянием чата и транслируем его вашим клиентам:

Вам никогда не придется беспокоиться о масштабе или инфраструктуре, мы позаботимся обо всем этом для вас.
Возможно, лучший способ изучить Чаткит - начать строительство, поэтому я настоятельно рекомендую вам следить за ними. По пути вы изучите лучшие практики при использовании Chatkit с React.
Этот учебник был написан так, чтобы вы могли следовать, шаг за шагом. Всего есть 12 шагов.
Вот краткое изложение, чтобы вы знали, чего ожидать:
Хорошо, давайте код!
Вместо того, чтобы начинать с абсолютной царапины, это прохождение основано на минимальном шаблоне стартового движения:

Как вы можете видеть, шаблон стартера не содержит никакой интересной логики - просто шаблон, который нам нужно для запуска приложения React и простого сервера узлов.
"Сервер? Никто не упомянул сервер!"
Если вы не слишком знакомы с узлом, не волнуйтесь? После следующего раздела нам не нужно будет касаться сервера.
Чтобы начать, загрузите шаблон стартера, а затем запустите npm install :
git clone https://github.com/pusher/build-a-slack-clone-with-react-and-pusher-chatkit chatkit-tutorial
cd chatkit-tutorial
npm install
(Примечание. Чтобы увидеть завершенный код, вы можете просмотреть completed ветвь или запустить git checkout complete Locally.)
(Также примечание: этот учебник предполагает использование npm , но эквивалентные команды yarn также будут работать.)
Теперь вы скачали шаблон стартера, давайте создадим экземпляр Chatkit.
Чтобы создать свой собственный экземпляр Chatkit, зайдите в панель инструментов и нажмите «Создать новый» :

Дайте вашему экземпляру любое имя (я назвал мой «React Catt Tutorial»), затем обратите внимание на ваш локатор экземпляра и секретный ключ на вкладке Keys . Они понадобятся они оба в следующем разделе.
Хотя большинство взаимодействий будут происходить на клиенте, Chatkit также нуждается в сервере, чтобы безопасно создавать и управлять пользователями:

Мы не будем аутентифицировать пользователей в этом уроке, но нам все еще нужно определить маршрут, который, когда их называют, создает пользователя Chatkit.
Начните с установки @pusher/chatkit-server :
npm install --save @pusher/chatkit-server
Затем обновить ./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}`)
}
})Не забудьте заменить «ваш локатор экземпляра» и «ваш ключ» на свои собственные значения.
Здесь есть что распаковать, начиная с вершины:
Chatkit с @pusher/chatkit-serverchatkit , используя локатор экземпляра и ключ, который мы отметили на предыдущем шаге/users мы берем username и создаем пользователя Chatkit через наш экземпляр chatkit/authenticate для их аутентификации. Сервер должен ответить токеном (возвращается chatkit.authenticate ), если запрос действителен. В нашем случае мы - наивно - предположим, что все они говорят, что они есть, и вернем токен из chatkit.authenticate , несмотря ни на что.БУМ?! Это все, что нам нужно сделать на сервере. Давайте перейдем к клиенту ...
Когда кто -то загружает приложение, мы хотим спросить его, кто он.
После того, как они нажмут «Отправить» , мы отправим их имя пользователя на сервер (на маршрут /users , который мы только что определили) и создадим пользователя Chatkit, если его не существует.
Чтобы собрать имя пользователя, создайте компонент под названием UsernameForm.js in in ./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 Затем обновить 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 npm start , и вы увидите, что экран отображается:

Начиная с вершины App.js :
UsernameForm . Это, вероятно, выглядит для вас знакомым, потому что он использует общий шаблон реагирования, называемый контролируемыми компонентами. Вы можете узнать больше о React Forms здесьrender мы отображаем UsernameForm и поднимаем обработчик событий onUsernameSubmittedonUsernameSubmitted , мы отправляем запрос на сообщение /users маршрут, который мы только что определили. Если запрос успешно, мы обновляем this.state.currentUsername , чтобы мы могли ссылаться на его позже; В противном случае мы console.error на ошибку На данный момент мы отображаем UsernameForm , и он занимает весь экран (см. Вышеупомянутый скриншот).
Как только имя пользователя будет отправлено, мы захотим перейти на другой экран, а именно на экран чата.
Чтобы сделать это, нам сначала нужно создать компонент ChatScreen.js в ./src :
+ import React, { Component } from 'react'
+
+ class ChatScreen extends Component {
+ render() {
+ return (
+ <div>
+ <h1>Chat</h1>
+ </div>
+ )
+ }
+ }
+
+ export default ChatScreen Затем обновить 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 Вместо того, чтобы использовать маршрутизатор, мы условно отображаем экран на основе this.state.currentScreen .
Ранее мы установили @pusher/chatkit-server . Теперь мы находимся в клиентской стране, вам также нужно установить @pusher/chatkit-client :
npm install --save @pusher/chatkit-client
Затем обновите 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 ChatScreenНе забудьте заменить «ваш локатор экземпляра» на ваш, который вы отмечали ранее.
Опять же, начиная с вершины:
ChatkitChatManager с помощью нашего instanceLocator , userId ( TokenProvider this.props.currentUsername . TokenProvider указывает на маршрут /authenticate который мы определили ранееChatManager был инициализирован, мы можем позвонить в connect . connect происходит асинхронно, и Promise возвращается. Если вы точно выполнили эти шаги, вы подключитесь. При этом, следите за любой console.error При использовании Чаткита все сообщения отправляются в комнату Чаткита.
Номера могут быть созданы программно (на сервере или клиенте с помощью createRoom ) или в инспекторе панели инструментов.
Создание комнат от инспектора на самом деле не является хорошей практикой (в основном это предназначено для тестирования), но для целей этого пошагового руководства мы все равно сделаем это.
На приборной панели отправляйтесь на вкладку Console , где вы найдете инспектора и создадите пользователя с любым именем. Я назову свой «администратор».
Затем создайте комнату под названием «General»:

Очень важно отметить уникальный идентификатор комнаты, выделенный выше.
Этот шаг знаменует собой значительный момент в прохождении.
Теперь у нас есть нашу пакет, мы можем быстро начать создавать функции чата.
В будущем мы разбим каждую функцию на независимую (многоразовую, если хотите!) Реактировать компоненты:

Мы создадим каждый компонент по мере продвижения вперед, но чтобы упростить учебник, давайте начнем базовую компонент пользовательского интерфейса сейчас:
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 ChatScreenЕсли вы запустите приложение сейчас, вы увидите основную планировку:

Потрясающий!
Я очень рад показать вам это!
Теперь у нас есть соединение Chatkit , функции строительного чата становятся такими же простыми, как подключать события Chatkit к компонентам пользовательского интерфейса. Здесь, позвольте мне показать вам.
Во -первых, создайте компонент MessageList.js без сохранения в ./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 Затем обновите 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 ChatScreenНе забудьте заменить свой идентификатор комнаты своим собственным идентификатором комнаты, который вы отмечали ранее.
Давайте разберем это:
currentUser , который представляет текущего подключенного пользователяcurrentUsersubscribeToRoom на currentUser ( currentUser.subscribeToRoom )subscribeToRoom который принимает обработчик событий, называемый onMessage , который называется в режиме реального времени каждый раз, когда прибывает новое сообщениеmessageLimit составляет 100 , onMessage также называется задним числом для до 100 самых последних сообщений. На практике это означает, что если вы обновите страницу, вы увидите до 100 самых последних сообщений чатаМы в броске!
Далее, давайте позволим пользователям отправлять сообщения, сначала создав компонент SendMessageForm.js в ./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 Затем - вы уже догадались - обновить 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 Компонент SendMessageForm , по сути, такой же, как и компонент WhatIsYourUsernameForm , который мы определили ранее.
Когда отправляется SendMessageForm , мы получаем доступ к this.state.currentUser и вызову sendMessage (помните, что большинство взаимодействий происходит на currentUser )
Вы, вероятно, можете увидеть появление шаблона ...
ChatScreen - это компонент контейнера , который управляет нашим состоянием приложения и производит пользовательский интерфейс с использованием презентации - обычно без хранения - компонентов. Большая часть нашего кода включает в себя подключение событий Чаткита и связанных с ними данных для реагирования компонентов пользовательского интерфейса.
Если вы когда -либо пытались реализовать свои собственные индикаторы печати, вы будете знать, что это может быть сложно. В целом, больше функций в реальном времени означает больше данных и больше подключений для управления.
С Чаткитом вы можете добавить индикаторы печати без особых усилий.
Начните с создания компонента TypingIndicator.js в ./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 Затем обновите 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 ChatScreenПри использовании Чаткита индикаторы печатают до двух фундаментальных действий:
currentUser.userIsTyping Когда текущий пользователь начинает печатать; затем,userStartedTyping и userStoppedTypingИ это в значительной степени.
"Но Алекс, как насчет того, когда пользователь перестает печатать?"
Это очень хороший вопрос.
Чаткит такой умный. Если служба не получает событие userIsTyping через несколько секунд, он предполагает, что currentUser прекратил печатать. Поэтому нет необходимости вручную поднимать событие, когда кто -то перестает печатать. Довольно гладко, верно?
Вы можете почувствовать импульс? Почти сделано сейчас?
Чтобы закончить приложение чата, давайте использовать функцию Chatkit «Кто онлайн», чтобы составить список пользователей и их статус в режиме реального времени.
Начните с создания компонента WhosOnlineList.js в /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 Тогда - в последний раз? - Обновить 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 Управление состоянием ваших пользователей в состоянии React может быть немного хитрым, поэтому мы управляем им для вас в currentRoom.users .
Поскольку пользователи подключаются и отключаются, это свойство динамически обновляется. Другими словами, currentRoom.users всегда должны пересматривать текущее состояние вашего приложения для чата.
Поэтому, когда пользователи выходят в интернет или выходят в автономном режиме ( onPresenceChange ), или новые пользователи присоединяются ( onUserAdded ), все, что нам нужно сделать, это позвонить в forceUpdate , который говорит React для оценки currentRoom.users и обновления пользовательского интерфейса.
Опять же, это действительно сводится к проводке простых данных и событий, чтобы реагировать компоненты, и это все, ребята!
В этом прохождении вы построили полное приложение в чате с
Поскольку мы использовали Чаткит, мы также получаем некоторые бонусные функции бесплатно:
Мы написали достаточное количество кода, но ничто из этого не было особенно сложным.
У Чаткита есть минимальный, но мощный API, который управляет всеми нашими данными чата для нас. Все, что нам нужно было сделать, это взять эти данные и отображать их для пользователя.
Хотите продолжать строить? Почему бы не добавить квитанции с богатой медиа -поддержкой и прочитать квитанции? Чаткит поддерживает оба:
Вы также можете быть заинтересованы в проверке нашей мощной демонстрации Chatkit Slack (250+ звезд ️). Это похоже на приложение, которое мы только что построили, но более завершены.
Что вы будете строить с Чаткитом? Мы хотели бы увидеть! Ваша отзывы направляет нас в улучшение Чаткита. Дайте нам знать, что помогает вам достичь ваших целей, что мешает вам, или что не хватает.