ในบทช่วยสอนนี้คุณจะได้เรียนรู้วิธีสร้างแอพแชทด้วย React และ Chatkit
เมื่อเราทำเสร็จแล้วเราจะมีแอปพลิเคชันแชทที่สมบูรณ์ด้วย ตัวบ่งชี้การพิมพ์ รายการ "Who's Online" และ ประวัติข้อความ :

หากคุณคิดว่าสิ่งนี้ฟังดูเป็นสิ่งที่ต้องใช้ในการสอนครั้งเดียวคุณมักจะพูดถูก!
อย่างไรก็ตามเนื่องจากเราจะใช้ Chatkit เราจึงสามารถมุ่งเน้นไปที่รหัสปฏิกิริยาส่วนหน้าได้มากหรือน้อยในขณะที่ Chatkit ทำการยกหนัก
Chatkit เป็น API โฮสต์ที่ช่วยให้คุณสร้างคุณสมบัติการแชทที่น่าประทับใจลงในแอปพลิเคชันของคุณด้วยรหัสน้อยลง คุณสมบัติเช่น
การใช้ SDK แบบข้ามแพลตฟอร์มของเราข้อมูลการแชททั้งหมดจะถูกส่งไปยัง API ที่โฮสต์ของเราซึ่งเราจัดการสถานะการแชทและออกอากาศไปยังลูกค้าของคุณ:

คุณจะไม่ต้องกังวลเกี่ยวกับขนาดหรือโครงสร้างพื้นฐานเราดูแลทุกอย่างให้คุณ
บางทีวิธีที่ดีที่สุดในการเรียนรู้ Chatkit คือการเริ่มสร้างดังนั้นฉันขอแนะนำให้คุณติดตาม ระหว่างทางคุณจะได้เรียนรู้แนวปฏิบัติที่ดีที่สุดเมื่อใช้ Chatkit กับ React
บทช่วยสอนนี้เขียนขึ้นเพื่อให้คุณสามารถติดตามได้ทีละขั้นตอน มีทั้งหมด 12 ขั้นตอน
นี่คือบทสรุปที่รวดเร็วเพื่อให้คุณรู้ว่าจะคาดหวังอะไร:
เอาล่ะรหัสกันเถอะ!
แทนที่จะเริ่มจากรอยขีดข่วนอย่างแน่นอนคำแนะนำนี้ขึ้นอยู่กับเทมเพลตเริ่มต้นน้อยที่สุด:

อย่างที่คุณเห็นเทมเพลตสตาร์ทเตอร์ไม่มีตรรกะที่น่าสนใจ - เพียงแค่หม้อไอน้ำเราต้องเรียกใช้แอปพลิเคชันปฏิกิริยาและเซิร์ฟเวอร์โหนดอย่างง่าย
"เซิร์ฟเวอร์ไม่มีใครพูดถึงเซิร์ฟเวอร์!"
หากคุณไม่คุ้นเคยกับโหนดไม่ต้องกังวล? หลังจากส่วนถัดไปเราไม่จำเป็นต้องแตะเซิร์ฟเวอร์
หากต้องการเริ่มต้นให้ดาวน์โหลดเทมเพลตสตาร์ทเตอร์จากนั้นเรียกใช้ 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 ของคุณเองมุ่งหน้าไปที่แผงควบคุมและกด สร้างใหม่ :

ให้ชื่อของคุณชื่อใด ๆ (ฉันเรียกว่า "การสอนการแชทแบบตอบโต้") จากนั้นจดบันทึกตัว ระบุตำแหน่งอินสแตนซ์ และ คีย์ลับ ในแท็บ คีย์ เราจะต้องการพวกเขาทั้งสองในส่วนถัดไป
ในขณะที่การโต้ตอบส่วนใหญ่จะเกิดขึ้นกับไคลเอนต์ 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 ใน ./src/components/ 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 และเชื่อมต่อตัวจัดการเหตุการณ์ 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 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 ของเรา (จาก this.props.currentUsername ) และ TokenProvider ที่กำหนดเอง TokenProvider ชี้ไปที่เส้นทาง /authenticate ที่เรากำหนดไว้ก่อนหน้านี้ChatManager เริ่มต้นแล้วเราสามารถโทรหา connect connect เกิดขึ้นแบบอะซิงโครนัสและ Promise จะถูกส่งคืน หากคุณทำตามขั้นตอนเหล่านี้อย่างแน่นอนคุณจะเชื่อมต่อ ที่ถูกกล่าวว่าระวัง console.error ใด ๆ เมื่อใช้ chatkit ข้อความทั้งหมดจะถูกส่งไปยังห้อง Chatkit
ห้องสามารถสร้างแบบโปรแกรมได้ (บนเซิร์ฟเวอร์หรือไคลเอนต์โดยใช้ createRoom ) หรือในเครื่องตรวจสอบแดชบอร์ด
การสร้างห้องพักจากผู้ตรวจสอบไม่ใช่วิธีปฏิบัติที่ดีจริงๆ (เป็นส่วนใหญ่สำหรับการทดสอบ) แต่เพื่อจุดประสงค์ของคำแนะนำนี้เราจะทำมัน
ในแดชบอร์ดตรงไปที่แท็บ คอนโซล ที่คุณจะพบผู้ตรวจสอบและสร้างผู้ใช้ที่มีชื่อใด ๆ ฉันจะเรียกฉันว่า "ผู้ดูแลระบบ"
จากนั้นสร้างห้องที่เรียกว่า "ทั่วไป":

เป็นสิ่งสำคัญอย่างยิ่งที่จะต้องทราบ ID ห้อง ที่ไม่ซ้ำกันที่เน้นด้านบน
ขั้นตอนนี้นับเป็นจุดสำคัญในการแนะนำ
ตอนนี้เรามีหม้อไอน้ำของเราอยู่ในสถานที่เราสามารถเริ่มสร้างคุณสมบัติการแชทได้อย่างรวดเร็ว
ก้าวไปข้างหน้าเราจะแยกแต่ละฟีเจอร์ออกเป็นอิสระ (สามารถนำกลับมาใช้ใหม่ได้หากคุณต้องการ!) ส่วนประกอบตอบสนอง:

เราจะสร้างแต่ละองค์ประกอบตามที่เราไปด้วย แต่เพื่อให้การสอนง่ายขึ้นเล็กน้อยในการติดตามลองกำหนดเค้าโครง 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 คุณสมบัติการแชทกลายเป็นเรื่องง่ายเหมือนการเชื่อมต่อกิจกรรม Chatkit กับส่วนประกอบ UI ที่นี่ให้ฉันแสดงให้คุณเห็น
ขั้นแรกให้สร้างองค์ประกอบ 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 เป็น องค์ประกอบคอนเทนเนอร์ ที่จัดการสถานะแอปพลิเคชันของเราและแสดงผล UI โดยใช้การนำเสนอ - โดยปกติแล้วองค์ประกอบ รหัสส่วนใหญ่ของเราเกี่ยวข้องกับการเชื่อมต่อเหตุการณ์ Chatkit และข้อมูลที่เกี่ยวข้องเพื่อตอบสนองส่วนประกอบ UI
หากคุณเคยพยายามใช้ตัวบ่งชี้การพิมพ์ของคุณเองคุณจะรู้ว่ามันอาจจะยุ่งยาก โดยทั่วไปคุณสมบัติเรียลไทม์มากขึ้นหมายถึงข้อมูลที่มากขึ้นและการเชื่อมต่อที่มากขึ้นในการจัดการ
ด้วย Chatkit คุณสามารถเพิ่มตัวบ่งชี้การพิมพ์ได้ด้วยความพยายามเพียงเล็กน้อย
เริ่มต้นด้วยการสร้างส่วนประกอบ 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เมื่อใช้ chatkit ตัวบ่งชี้การพิมพ์เดือดลงไปสองการกระทำพื้นฐาน:
currentUser.userIsTyping เมื่อผู้ใช้ปัจจุบันเริ่มพิมพ์ แล้ว,userStartedTyping และ userStoppedTypingและนั่นก็สวยมาก
"แต่อเล็กซ์แล้วผู้ใช้ จะหยุด พิมพ์ล่ะ"
นั่นเป็นคำถามที่ดีมาก
Chatkit ฉลาดเช่นนั้น หากบริการไม่ได้รับเหตุการณ์ userIsTyping หลังจากไม่กี่วินาทีก็จะถือว่า currentUser หยุดการพิมพ์ ดังนั้นจึงไม่จำเป็นต้องเพิ่มเหตุการณ์ด้วยตนเองเมื่อมีคนหยุดพิมพ์ สวยลื่นใช่มั้ย
คุณรู้สึกถึงแรงผลักดันได้ไหม? เกือบเสร็จแล้ว?
หากต้องการจบแอพแชทให้เสร็จสิ้นคุณลักษณะ "Who's Online" ของ 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 และอัปเดต UI
อีกครั้งมันเดือดลงไปที่การเดินสายข้อมูลและกิจกรรมง่าย ๆ เพื่อตอบสนองส่วนประกอบและนั่นคือทั้งหมดที่คน!
ในคำแนะนำนี้คุณสร้างแอปพลิเคชันแชทที่สมบูรณ์ด้วย
เนื่องจากเราใช้ Chatkit เรายังได้รับคุณสมบัติโบนัสฟรี:
เราเขียนรหัสจำนวนพอสมควร แต่ไม่มีสิ่งใดที่ซับซ้อนเป็นพิเศษ
Chatkit มี API ขั้นต่ำ แต่ทรงพลังซึ่งจัดการข้อมูลการแชททั้งหมดของเราสำหรับเรา สิ่งที่เราต้องทำคือใช้ข้อมูลนั้นและแสดงผลสำหรับผู้ใช้
ต้องการสร้างต่อไป? ทำไมไม่เพิ่มการสนับสนุนสื่อที่หลากหลายและอ่านใบเสร็จรับเงิน? Chatkit รองรับทั้งสอง:
คุณอาจสนใจที่จะตรวจสอบการสาธิต Chatkit Slack อันทรงพลังของเรา (250+ ดาว️) มันคล้ายกับแอปพลิเคชันที่เราเพิ่งสร้าง แต่สมบูรณ์กว่า
คุณจะสร้างอะไรกับ Chatkit? เราชอบที่จะเห็น! ความคิดเห็นของคุณแนะนำเราในการปรับปรุง Chatkit แจ้งให้เราทราบว่าอะไรช่วยให้คุณบรรลุเป้าหมายสิ่งที่กำลังมาขวางทางคุณหรือสิ่งที่ขาดหายไป