在本教程中,您将学习如何使用React和Chatkit构建聊天应用程序。
完成后,我们将拥有一个聊天应用程序,其中包含打字指标, “谁在线”列表和消息历史记录:

如果您认为这听起来像是在一个教程中可以解决的很多,那么您通常是对的!
但是,因为我们将使用Chatkit,所以我们或多或少地专注于前端反应代码,而Chatkit进行了繁重的工作。
Chatkit是托管的API,可帮助您使用更少的代码构建令人印象深刻的聊天功能。诸如
使用我们的跨平台SDK,所有聊天数据均发送到我们的托管API,我们管理聊天状态并将其广播给您的客户:

您永远不必担心规模或基础设施,我们为您服务。
学习Chatkit的最好方法是开始建造,因此我强烈建议您跟随。一路上,将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 。)
(还要注意:本教程假设使用npm ,但等效yarn命令也将起作用。)
现在,您已经下载了入门模板,让我们创建一个chatkit实例。
要创建自己的chatkit实例,请前往仪表板并击中创建新的:

给您的实例任何名称(我称我的“ React Chat教程”),然后记下您的实例定位器和“键”选项卡中的秘密键。我们将在下一部分中都需要它们。
尽管大多数交互将发生在客户端上,但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}`)
}
})切记用自己的值替换“您的实例定位器”和“密钥” 。
从顶部开始,这里有很多要打开包装:
@pusher/chatkit-server导入Chatkitchatkit实例/users路由中,我们使用一个username并通过我们的chatkit实例创建chatkit用户/authenticate以对其进行身份验证。如果请求有效,服务器需要用令牌响应(由chatkit.authenticate返回)。在我们的情况下,我们 - 天真 - 假设每个人都是他们说的人,并从chatkit.authenticate返回一个令牌。繁荣?!这就是我们在服务器上需要做的全部。让我们继续前进...
当有人加载该应用程序时,我们想问他们他们是谁。
一旦达到提交,我们将将其用户名发送到服务器(我们刚刚定义的/users路由),并在不存在的情况下创建chatkit用户。
要收集用户的名称,请创建一个名为UsernameForm.js 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表格的更多信息render函数中,我们渲染UsernameForm并连接onUsernameSubmitted事件处理程序onUsernameSubmitted时,我们将邮政请求发送给我们刚刚定义的/users路由。如果请求成功,我们将更新this.state.currentUsername ,以便以后引用它;否则,我们console.error错误目前,我们渲染了UsernameForm ,它占据了整个屏幕(请参见上面的屏幕截图)。
提交用户名后,我们将要过渡到其他屏幕 - 即聊天屏幕。
为此,我们首先需要在./src中创建一个ChatScreen.js组件:
+ 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请记住,将“您的实例定位器”替换为您之前指出的。
同样,从顶部开始:
ChatkitinstanceLocator , userId (来自this.props.currentUsername )和自定义的TokenProvider实例化我们的chatkit ChatManager 。 TokenProvider指向我们之前定义的/authenticate路由ChatManager后,我们可以调用connect 。 connect发生异步发生,并返回Promise 。如果您准确地遵循了这些步骤,则将连接。话虽这么说,请注意任何console.error如果您错过了什么,请使用Chatkit时,所有消息都将发送到Chatkit室。
可以通过编程(使用createRoom在服务器或客户室)或仪表板检查员进行编程创建房间。
从检查员创建房间并不是一个好练习(主要是用于测试),但是为了这次演练,我们还是要这样做。
在仪表板中,前往“控制台”选项卡,您可以在其中找到检查器并使用任何名称创建用户。我将我的称为“管理员”。
然后,创建一个称为“通用”的房间:

注意上面突出显示的独特房间ID确实很重要。
此步骤标志着演练的重要一点。
现在,我们已经制定了样板,我们可以迅速开始构建聊天功能。
展望未来,我们将将每个功能分解为独立(如果需要的话,可重复使用!)React组件:

我们将在运行时创建每个组件,但是为了使教程更容易遵循,让我们现在列出基本的组件UI布局:
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连接,构建聊天功能变得像将聊天俱乐部事件相连为UI组件一样简单。在这里,让我告诉你。
首先,在./src/components中创建一个无状态MessageList.js组件:
+ 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请记住,将您的房间ID替换为您之前提到的房间ID。
让我们将其分解:
currentUser使用者对象currentUser上currentUser上拨打subscribeToRoom ( currentUser.subscribeToRoom )subscribeToRoom采用一个名为onMessage的事件处理程序,每次到达新消息时,都会实时调用messageLimit指定为100 , onMessage最多可追溯为100最新消息。在实践中,这意味着,如果您刷新页面,您将看到多达100最新聊天消息我们正在滚!
接下来,让我们允许用户通过首先创建SendMessageForm.js组件来发送消息: ./src/components 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是一个容器组件,它可以管理我们的应用程序状态,并使用介绍(通常是无状态的)组件呈现UI。我们的大多数代码都涉及连接Chatkit事件及其相关数据以反应UI组件。
如果您曾经尝试实现自己的打字指标,那么您会知道这可能很棘手。通常,更多的实时功能意味着更多的数据和更多的连接要管理。
使用Chatkit,您几乎可以添加打字指标。
首先在./src/components中创建TypingIndicator.js组件:
+ 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使用Chatkit时,打字指标归结为两个基本措施:
currentUser.userIsTyping ;然后,userStartedTyping和userStoppedTyping活动就是这样。
“但是亚历克斯,用户何时停止打字呢?”
这是一个很好的问题。
Chatkit这样聪明。如果该服务在几秒钟后没有接收userIsTyping事件,则假设currentUser使用者已停止键入。因此,当有人停止打字时,无需手动提出活动。漂亮的光滑,对吧?
你能感觉到动力吗?现在几乎完成了吗?
要完成聊天应用程序,让我们使用Chatkit的“谁在线”功能来渲染用户列表及其实时在线状态。
首先创建/src/components中的WhosOnlineList.js组件:
+ 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 ,它告诉reacts revers inture currentRoom.users并更新UI。
同样,这确实归结为对一些简单的数据和事件进行接线以反应组件,仅此而已!
在本演练中,您构建了一个完整的聊天应用程序
因为我们使用了chatkit,所以我们也免费获得一些奖励功能:
我们编写了相当多的代码,但这都不是特别复杂。
Chatkit具有最小但功能强大的API,可以为我们管理我们所有的聊天数据。我们要做的就是获取这些数据并为用户渲染。
想继续建造吗?为什么不添加丰富的媒体支持并阅读收据? Chatkit都支持:
您可能也有兴趣查看我们强大的Chatkit Slack演示(250多个星星️)。它类似于我们刚刚构建但更完整的应用程序。
您将使用Chatkit构建什么?我们很想看看!您的反馈指导我们改善Chatkit。让我们知道什么可以帮助您实现目标,妨碍您遇到的目标。