في هذا البرنامج التعليمي ، ستتعلم كيفية إنشاء تطبيق دردشة مع React و Chatkit.
عندما ننتهي ، سيكون لدينا تطبيق دردشة كاملة مع مؤشرات الكتابة ، وقائمة "من عبر الإنترنت" ، وسجل الرسائل :

إذا كنت تعتقد أن هذا يبدو وكأنه الكثير لتتعامل معه في برنامج تعليمي واحد ، فستكون عادة على حق!
ومع ذلك ، نظرًا لأننا سنستخدم Chatkit ، يمكننا التركيز بشكل حصري على رمز React في الواجهة الأمامية بينما يقوم Chatkit بالرفع الثقيل.
Chatkit هي واجهة برمجة تطبيقات مستضافة تساعدك على بناء ميزات دردشة رائعة في تطبيقاتك باستخدام رمز أقل. ميزات مثل ،
باستخدام SDKs عبر المنصات ، يتم إرسال جميع بيانات الدردشة إلى واجهة برمجة التطبيقات المستضافة حيث ندير حالة الدردشة ونبثها لعملائك:

لن تضطر أبدًا للقلق بشأن الحجم أو البنية التحتية ، فنحن نعتني بكل ذلك من أجلك.
ربما تكون أفضل طريقة لتعلم Chatkit هي البدء في البناء ، لذلك أوصي بشدة بالمتابعة. على طول الطريق ، ستتعلم أفضل الممارسات عند استخدام chatkit مع React.
تمت كتابة هذا البرنامج التعليمي بحيث يمكنك متابعته ، خطوة بخطوة. هناك 12 خطوة في المجموع.
إليك المتهدمة السريعة حتى تعرف ماذا تتوقع:
حسنا ، دعونا رمز!
بدلاً من البدء من الخدش المطلق ، يعتمد هذا الإرشاد على قالب بداية الحد الأدنى:

كما ترون ، لا يحتوي قالب المبتدئين على أي منطق مثير للاهتمام - فقط BoilerPlate نحتاج إلى تشغيل تطبيق 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 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 في ./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 ونربط معالج الأحداث 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 (من this.props.currentUsername ) ، و TokenProvider مخصص. يشير TokenProvider إلى مسار /authenticate الذي حددناه سابقًاChatManager ، يمكننا استدعاء connect . يحدث connect بشكل غير متزامن ويتم إرجاع Promise . إذا كنت قد اتبعت هذه الخطوات بالضبط ، فستتصل. ومع ذلك ، احترس من أي console.error في حال فاتتك شيء ما عند استخدام Chatkit ، يتم إرسال جميع الرسائل إلى غرفة Chatkit.
يمكن إنشاء الغرف برمجيًا (على الخادم أو العميل باستخدام createRoom ) ، أو في مفتش لوحة القيادة.
إن إنشاء غرف من المفتش ليس حقًا ممارسة جيدة (فهي مخصصة بشكل أساسي للاختبار) ولكن لغرض هذا الإرشاد ، سنفعل ذلك على أي حال.
في لوحة القيادة ، توجه إلى علامة تبويب وحدة التحكم ، حيث ستجد المفتش وإنشاء مستخدم بأي اسم. سأتصل بي "المشرف".
ثم ، قم بإنشاء غرفة تسمى "عام":

من المهم حقًا ملاحظة معرف الغرفة الفريد الموضح أعلاه.
هذه الخطوة تمثل نقطة مهمة في التجول.
الآن لدينا في مكاننا ، يمكننا البدء بسرعة في بناء ميزات الدردشة.
للمضي قدمًا ، سنقوم بتقسيم كل ميزة إلى مكونات مستقلة (قابلة لإعادة الاستخدام ، إذا كنت تريد!):

سنقوم بإنشاء كل مكونات مع تقدمنا ، ولكن لجعل البرنامج التعليمي أسهل بعض الشيء ، دعنا نضع تخطيط واجهة المستخدم الأساسية الآن:
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 و Call sendMessage (تذكر أن معظم التفاعلات تحدث على currentUser )
ربما يمكنك رؤية نمط ناشئ ...
ChatScreen هي مكون حاوية يدير حالة تطبيقنا ويجعل واجهة المستخدم باستخدام المكونات عديمة الجنسية - العادية عادة. تتضمن معظم التعليمات البرمجية الخاصة بنا تثبيت أحداث Chatkit وبياناتها المرتبطة بها لتفاعل مكونات واجهة المستخدم.
إذا حاولت تنفيذ مؤشرات الكتابة الخاصة بك ، فستعرف أنه قد يكون صعبًا. بشكل عام ، تعني المزيد من الميزات في الوقت الفعلي المزيد من البيانات والمزيد من الاتصالات للإدارة.
مع 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 State أمرًا صعبًا بعض الشيء ، لذا فإننا نديرها لك في currentRoom.users .
مع توصيل المستخدمين ويفصلون ، يتم تحديث هذه الخاصية ديناميكيًا. وبعبارة أخرى ، يجب على currentRoom.users إعادة تكوين الحالة الحالية لتطبيق الدردشة الخاص بك.
لذلك ، عندما يأتي المستخدمون عبر الإنترنت أو يذهبون إلى عدم الاتصال ( onPresenceChange ) ، أو ينضم المستخدمون الجدد إلى ( onUserAdded ) ، كل ما علينا فعله هو Call forceUpdate الذي يخبر React لتقييم currentRoom.users وتحديث واجهة المستخدم.
مرة أخرى ، فإنه يتلخص حقًا في توصيل بعض البيانات والأحداث البسيطة لتفاعل المكونات وهذا كل شيء ، أيها الناس!
في هذا التجول ، قمت ببناء تطبيق دردشة كامل مع
لأننا استخدمنا Chatkit ، نحصل أيضًا على بعض ميزات المكافآت مجانًا:
لقد كتبنا قدرًا لا بأس به من التعليمات البرمجية ، لكن لم يكن أي منها معقدًا بشكل خاص.
لدى Chatkit الحد الأدنى من واجهة برمجة التطبيقات القوية التي تدير جميع بيانات الدردشة الخاصة بنا. كل ما كان علينا فعله هو أخذ هذه البيانات وتقديمها للمستخدم.
تريد الاستمرار في البناء؟ لماذا لا تضيف دعم وسائل الإعلام الغنية وقراءة الإيصالات؟ Chatkit يدعم كلاهما:
قد تكون مهتمًا أيضًا بالتحقق من Demo Chatkit Slack القوية (250+ نجمة ️). إنه مشابه للتطبيق الذي قمنا بإنشائه فقط ولكن أكثر اكتمالا.
ماذا ستبني مع chatkit؟ نود أن نرى! ملاحظاتك يرشدنا في تحسين Chatkit. اسمحوا لنا أن نعرف ما الذي يساعدك على الوصول إلى أهدافك ، أو ما الذي يعترض طريقك ، أو ما هو مفقود.