Project Templates
Social Network
แชทแบบเรียลไทม์สำหรับเครือข่ายสังคมของคุณ
50 นาที
บทนำ ในบทเรียนนี้ คุณจะได้เรียนรู้วิธีการสร้างระบบการส่งข้อความแบบเรียลไทม์สำหรับแอปพลิเคชันเครือข่ายสังคมของคุณโดยใช้ back4app คุณจะสร้างฟังก์ชันการแชทที่สมบูรณ์ซึ่งอนุญาตให้ผู้ใช้ส่งและรับข้อความได้ทันที ดูตัวบ่งชี้การพิมพ์ และจัดการการสนทนา ฟีเจอร์ที่จำเป็นสำหรับแพลตฟอร์มสังคมที่น่าสนใจ back4app เป็นแพลตฟอร์ม backend as a service (baas) ที่สร้างขึ้นบน parse server ซึ่งมีความสามารถในการทำงานแบบเรียลไทม์ที่ทรงพลังผ่านฟีเจอร์ live query ด้วยโครงสร้างพื้นฐานแบบเรียลไทม์ของ back4app คุณสามารถสร้างระบบการส่งข้อความที่ตอบสนองได้โดยไม่ต้องจัดการกับเซิร์ฟเวอร์ websocket ที่ซับซ้อนหรือปัญหาการขยายตัว เมื่อสิ้นสุดบทเรียนนี้ คุณจะได้สร้างระบบการส่งข้อความที่ใช้งานได้จริงซึ่งคล้ายกับที่ใช้ใน back4gram แอปพลิเคชันเครือข่ายสังคม คุณจะดำเนินการสร้างการสนทนา การแลกเปลี่ยนข้อความแบบเรียลไทม์ ตัวบ่งชี้การพิมพ์ และการค้นหาผู้ใช้ ซึ่งจะมอบประสบการณ์การสื่อสารที่ราบรื่นให้กับผู้ใช้ของคุณ back4gram project ค้นหา ที่นี่ โค้ดทั้งหมดสำหรับ โครงการตัวอย่างเครือข่ายสังคม ที่สร้างขึ้นด้วย back4app ข้อกำหนดเบื้องต้น ในการทำตามบทเรียนนี้ คุณจะต้องมี บัญชี back4app คุณสามารถลงทะเบียนสำหรับบัญชีฟรีที่ back4app com https //www back4app com โครงการ back4app ที่ตั้งค่าไว้ด้วย parse javascript sdk ที่เริ่มต้นแล้ว node js ติดตั้งอยู่ในเครื่องของคุณ ความรู้พื้นฐานเกี่ยวกับ javascript, react js, และ back4app/parse server ระบบการตรวจสอบสิทธิ์ที่มีการดำเนินการแล้ว หากคุณยังไม่ได้ตั้งค่านี้ โปรดดูที่ บทเรียนระบบการตรวจสอบสิทธิ์ https //www back4app com/docs/react/authentication tutorial ความคุ้นเคยกับ react hooks และวงจรชีวิตของคอมโพเนนต์ ขั้นตอนที่ 1 – เข้าใจความสามารถเรียลไทม์ของ back4app ก่อนที่เราจะเริ่มเขียนโค้ด มาทำความเข้าใจว่า back4app เปิดใช้งานฟังก์ชันการทำงานแบบเรียลไทม์ผ่านฟีเจอร์ live query ได้อย่างไร อธิบาย live query live query เป็นฟีเจอร์ของ parse server ที่อนุญาตให้ลูกค้าสมัครสมาชิกกับการค้นหาและรับการอัปเดตเมื่อมีวัตถุที่ตรงกับการค้นหานั้นถูกสร้างขึ้น อัปเดต หรือถูกลบ นี่เหมาะสำหรับการสร้างแอปพลิเคชันแบบเรียลไทม์ เช่น ระบบแชท นี่คือวิธีการทำงานของ live query ลูกค้าสมัครสมาชิกกับการค้นหาเฉพาะ (เช่น "ข้อความทั้งหมดในสนทนา x") เมื่อวัตถุที่ตรงกันถูกสร้างขึ้น อัปเดต หรือถูกลบบนเซิร์ฟเวอร์ live query จะส่งการแจ้งเตือนอัตโนมัติไปยังลูกค้าที่สมัครสมาชิกทั้งหมด ลูกค้าสามารถอัปเดต ui ของตนเพื่อตอบสนองต่อเหตุการณ์เหล่านี้ได้ ในบริบทของระบบการส่งข้อความ หมายความว่า เมื่อมีการส่งข้อความใหม่ ผู้ใช้ทั้งหมดในสนทนานั้นจะได้รับข้อความทันที เมื่อผู้ใช้เริ่มพิมพ์ ผู้ใช้อื่นสามารถเห็นตัวบ่งชี้การพิมพ์แบบเรียลไทม์ เมื่อข้อความถูกอ่าน ใบเสร็จการอ่านสามารถอัปเดตสำหรับผู้เข้าร่วมทั้งหมดได้ การตั้งค่าการค้นหาสดบน back4app ในการใช้การค้นหาสด คุณต้องเปิดใช้งานในแดชบอร์ด back4app ของคุณ เข้าสู่ระบบแดชบอร์ด back4app ของคุณ ไปที่การตั้งค่าเซิร์ฟเวอร์ > เว็บโฮสติ้งและการค้นหาสด เปิดใช้งานการค้นหาสด เพิ่มคลาสที่คุณต้องการใช้กับการค้นหาสด (ในกรณีของเรา "ข้อความ" และ "สถานะการพิมพ์") ถัดไป ในโค้ดฝั่งไคลเอนต์ของคุณ คุณต้องเริ่มต้นไคลเอนต์ live query // initialize parse with your back4app credentials parse initialize("your app id", "your javascript key"); parse serverurl = "https //parseapi back4app com/"; // initialize live query parse livequeryserverurl = "wss\ //your app id back4app io"; ตอนนี้เรามาออกแบบสคีมาของฐานข้อมูลสำหรับระบบการส่งข้อความของเรากันเถอะ โครงการ back4gram ค้นหา ที่นี่ โค้ดทั้งหมดสำหรับ โครงการตัวอย่างเครือข่ายสังคม ที่สร้างด้วย back4app ขั้นตอนที่ 2 – การออกแบบสคีมาของฐานข้อมูล สำหรับระบบการส่งข้อความของเรา เราจะต้องการคลาส parse หลายคลาส การสนทนา แสดงถึงการสนทนาระหว่างผู้ใช้สองคนหรือมากกว่า ข้อความ แสดงถึงข้อความแต่ละข้อความภายในการสนทนา สถานะการพิมพ์ ติดตามเมื่อผู้ใช้กำลังพิมพ์ในการสนทนา เรามาสร้างคลาสเหล่านี้ใน back4app กันเถอะ คลาสการสนทนา คลาสการสนทนาจะมีฟิลด์ดังต่อไปนี้ ผู้เข้าร่วม (อาร์เรย์ของพอยเตอร์ไปยังผู้ใช้) ผู้ใช้ที่เกี่ยวข้องในสนทนา ข้อความล่าสุด (สตริง) ข้อความล่าสุดที่ส่ง อัปเดตเมื่อ (วันที่) อัปเดตโดยอัตโนมัติโดย parse เมื่อบันทึกมีการเปลี่ยนแปลง คลาสข้อความ คลาสข้อความจะมี การสนทนา (พอยเตอร์ไปยังการสนทนา) การสนทนาที่ข้อความนี้เป็นของมัน ผู้ส่ง (พอยเตอร์ไปยังผู้ใช้) ผู้ใช้ที่ส่งข้อความ ข้อความ (สตริง) เนื้อหาของข้อความ สร้างเมื่อ (วันที่) สร้างโดยอัตโนมัติโดย parse เมื่อข้อความถูกส่ง คลาส typingstatus คลาส typingstatus จะติดตามตัวบ่งชี้การพิมพ์ ผู้ใช้ (ชี้ไปที่ผู้ใช้) ผู้ที่กำลังพิมพ์ การสนทนา (ชี้ไปที่การสนทนา) การสนทนาที่กำลังเกิดการพิมพ์ กำลังพิมพ์ (boolean) ว่าผู้ใช้กำลังพิมพ์อยู่หรือไม่ ตอนนี้ มาตั้งค่าโครงสร้างโปรเจกต์ของเราเพื่อดำเนินการระบบการส่งข้อความนี้กันเถอะ โปรเจกต์ back4gram ค้นหา ที่นี่ โค้ดทั้งหมดสำหรับ โปรเจกต์ตัวอย่างเครือข่ายสังคม ที่สร้างด้วย back4app ขั้นตอนที่ 3 – การตั้งค่าโครงสร้างโปรเจกต์ มาจัดระเบียบโค้ดของเราสำหรับระบบการส่งข้อความกันเถอะ เราจะมุ่งเน้นไปที่ส่วนประกอบที่สำคัญ src/ ├── components/ │ └── ui/ │ ├── toaster js │ └── avatar js ├── pages/ │ └── messagespage js ├── app js └── parseconfig js มาสร้าง toaster js สำหรับการแจ้งเตือนกันเถอะ // src/components/ui/toaster js export const toaster = { create ({ title, description, type }) => { // in a real app, you would use a proper toast notification component console log(`\[${type touppercase()}] ${title} ${description}`); alert(`${title} ${description}`); } }; และอัปเดต app js เพื่อรวมเส้นทางข้อความ // src/app js import react from 'react'; import { browserrouter as router, routes, route } from 'react router dom'; import messagespage from ' /pages/messagespage'; // import other pages function app() { return ( \<router> \<routes> \<route path="/messages" element={\<messagespage />} /> {/ other routes /} \</routes> \</router> ); } export default app; ตอนนี้ มามอบฟังก์ชันการส่งข้อความหลักกันเถอะ โปรเจกต์ back4gram ค้นหา ที่นี่ โค้ดทั้งหมดสำหรับ โปรเจกต์ตัวอย่างเครือข่ายสังคม ที่สร้างด้วย back4app ขั้นตอนที่ 4 – การสร้างส่วนประกอบหน้า messages ส่วนประกอบ messagespage js จะเป็นแกนหลักของระบบการส่งข้อความของเรา มันจะ แสดงรายการสนทนา อนุญาตให้ผู้ใช้ดูและส่งข้อความ แสดงตัวบ่งชี้การพิมพ์ เปิดใช้งานการค้นหาผู้ใช้เพื่อเริ่มการสนทนาใหม่ มาสร้างสิ่งนี้ทีละขั้นตอน // src/pages/messagespage js import react, { usestate, useeffect, useref } from 'react'; import { box, flex, input, button, vstack, text, avatar, heading, spinner, center, hstack, divider, } from '@chakra ui/react'; import { usenavigate } from 'react router dom'; import parse from 'parse/dist/parse min js'; import { toaster } from ' /components/ui/toaster'; function messagespage() { const \[message, setmessage] = usestate(''); const \[istyping, setistyping] = usestate(false); const \[isloading, setisloading] = usestate(true); const \[issending, setissending] = usestate(false); const \[currentuser, setcurrentuser] = usestate(null); const \[conversations, setconversations] = usestate(\[]); const \[activeconversation, setactiveconversation] = usestate(null); const \[messages, setmessages] = usestate(\[]); const \[users, setusers] = usestate(\[]); const \[searchquery, setsearchquery] = usestate(''); const \[showusersearch, setshowusersearch] = usestate(false); const \[processedmessageids, setprocessedmessageids] = usestate(new set()); const \[otherusertyping, setotherusertyping] = usestate(false); const messagesendref = useref(null); const livequerysubscription = useref(null); const typingstatussubscription = useref(null); const typingtimerref = useref(null); const navigate = usenavigate(); // check if user is authenticated useeffect(() => { const checkauth = async () => { try { console log('checking authentication '); const user = await parse user current(); if (!user) { console log('no user found, redirecting to login'); navigate('/login'); return; } console log('user authenticated ', user id, user get('username')); setcurrentuser(user); fetchconversations(user); } catch (error) { console error('error checking authentication ', error); navigate('/login'); } }; checkauth(); // clean up subscriptions when component unmounts return () => { if (livequerysubscription current) { livequerysubscription current unsubscribe(); } if (typingstatussubscription current) { typingstatussubscription current unsubscribe(); } if (typingtimerref current) { cleartimeout(typingtimerref current); } }; }, \[navigate]); // we'll implement the following functions next const fetchconversations = async (user) => { // coming up next }; const resetmessagestate = () => { // coming up next }; const fetchmessages = async (conversationid) => { // coming up next }; const setuplivequery = async (conversationid) => { // coming up next }; const setuptypingstatussubscription = async (conversationid) => { // coming up next }; const updatetypingstatus = async (istyping) => { // coming up next }; const sendmessage = async () => { // coming up next }; const searchusers = async (query) => { // coming up next }; const startconversation = async (userid) => { // coming up next }; // format time for messages const formatmessagetime = (date) => { return new date(date) tolocaletimestring(\[], { hour '2 digit', minute '2 digit' }); }; // format date for conversation list const formatconversationdate = (date) => { const now = new date(); const messagedate = new date(date); // if today, show time if (messagedate todatestring() === now\ todatestring()) { return messagedate tolocaletimestring(\[], { hour '2 digit', minute '2 digit' }); } // if this year, show month and day if (messagedate getfullyear() === now\ getfullyear()) { return messagedate tolocaledatestring(\[], { month 'short', day 'numeric' }); } // otherwise show full date return messagedate tolocaledatestring(); }; return ( \<flex h="100vh"> {/ we'll implement the ui next /} \</flex> ); } export default messagespage; ตอนนี้เรามา implement ฟังก์ชันแต่ละตัวที่จำเป็นสำหรับระบบการส่งข้อความของเรากันเถอะ back4gram โครงการ ค้นหา ที่นี่ โค้ดทั้งหมดสำหรับ โครงการตัวอย่างเครือข่ายสังคม ที่สร้างขึ้นด้วย back4app ขั้นตอนที่ 5 – ดึงการสนทนาของผู้ใช้ ก่อนอื่น มาดำเนินการ fetchconversations ฟังก์ชันที่โหลดการสนทนาทั้งหมดสำหรับผู้ใช้ปัจจุบัน const fetchconversations = async (user) => { setisloading(true); try { console log('fetching conversations for user ', user id); // query conversations where the current user is a participant const query = new parse query('conversation'); query equalto('participants', user); query include('participants'); query descending('updatedat'); const results = await query find(); console log('found conversations ', results length); // format conversations const formattedconversations = results map(conv => { const participants = conv get('participants'); // find the other participant (not the current user) const otherparticipant = participants find(p => p id !== user id); if (!otherparticipant) { console warn('could not find other participant in conversation ', conv id); return null; } return { id conv id, user { id otherparticipant id, username otherparticipant get('username'), avatar otherparticipant get('avatar') ? otherparticipant get('avatar') url() null }, lastmessage conv get('lastmessage') || '', updatedat conv get('updatedat') }; }) filter(boolean); // remove any null entries console log('formatted conversations ', formattedconversations); setconversations(formattedconversations); // if there are conversations, set the first one as active if (formattedconversations length > 0) { setactiveconversation(formattedconversations\[0]); fetchmessages(formattedconversations\[0] id); } } catch (error) { console error('error fetching conversations ', error); toaster create({ title 'error', description 'failed to load conversations', type 'error', }); } finally { setisloading(false); } }; ฟังก์ชันนี้ ค้นหาคลาสการสนทนาสำหรับการสนทนาที่ผู้ใช้ปัจจุบันเป็นผู้เข้าร่วม จัดรูปแบบผลลัพธ์เพื่อแสดงใน ui ตั้งค่าการสนทนาครั้งแรกเป็นการสนทนาแบบแอคทีฟหากมีอยู่ back4gram project ค้นหา ที่นี่ โค้ดทั้งหมดสำหรับ ตัวอย่างโปรเจกต์เครือข่ายสังคม ที่สร้างด้วย back4app ขั้นตอนที่ 6 – การจัดการข้อความและการอัปเดตแบบเรียลไทม์ ตอนนี้เรามาใช้ฟังก์ชันในการดึงข้อความและตั้งค่าอัปเดตแบบเรียลไทม์โดยใช้ live query const resetmessagestate = () => { console log('resetting message state'); setmessages(\[]); setprocessedmessageids(new set()); setotherusertyping(false); if (livequerysubscription current) { livequerysubscription current unsubscribe(); livequerysubscription current = null; console log('unsubscribed from live query in resetmessagestate'); } if (typingstatussubscription current) { typingstatussubscription current unsubscribe(); typingstatussubscription current = null; console log('unsubscribed from typing status subscription in resetmessagestate'); } }; const fetchmessages = async (conversationid) => { // reset message state to avoid any lingering messages or subscriptions resetmessagestate(); try { // query messages for this conversation const query = new parse query('message'); const conversation = new parse object('conversation'); conversation id = conversationid; query equalto('conversation', conversation); query include('sender'); query ascending('createdat'); const results = await query find(); // format messages const formattedmessages = results map(msg => ({ id msg id, text msg get('text'), sender { id msg get('sender') id, username msg get('sender') get('username') }, createdat msg get('createdat') })); // initialize the set of processed message ids const messageids = new set(formattedmessages map(msg => msg id)); // set state after processing all messages setmessages(formattedmessages); setprocessedmessageids(messageids); // set up live query subscription for new messages setuplivequery(conversationid); // set up typing status subscription setuptypingstatussubscription(conversationid); // scroll to bottom of messages settimeout(() => { if (messagesendref current) { messagesendref current scrollintoview({ behavior 'smooth' }); } }, 100); } catch (error) { console error('error fetching messages ', error); toaster create({ title 'error', description 'failed to load messages', type 'error', }); } }; ตอนนี้เรามาใช้การสมัครสมาชิก live query สำหรับการอัปเดตข้อความแบบเรียลไทม์ const setuplivequery = async (conversationid) => { // capture the current user in a closure to avoid null reference later const captureduser = currentuser; // unsubscribe from previous subscription if exists if (livequerysubscription current) { livequerysubscription current unsubscribe(); console log('unsubscribed from previous live query'); } try { console log('setting up live query for conversation ', conversationid); // create a query that will be used for the subscription const query = new parse query('message'); const conversation = new parse object('conversation'); conversation id = conversationid; query equalto('conversation', conversation); query include('sender'); console log('created query for message class with conversation id ', conversationid); // subscribe to the query livequerysubscription current = await query subscribe(); console log('successfully subscribed to live query'); // handle connection open livequerysubscription current on('open', () => { console log('live query connection opened for conversation ', conversationid); }); // handle new messages livequerysubscription current on('create', (message) => { console log('new message received via live query ', message id); // check if we've already processed this message if (processedmessageids has(message id)) { console log('skipping duplicate message ', message id); return; } // format the new message const newmessage = { id message id, text message get('text'), sender { id message get('sender') id, username message get('sender') get('username') }, createdat message get('createdat') }; console log('formatted new message ', newmessage); // add the message id to the set of processed ids setprocessedmessageids(previds => { const newids = new set(previds); newids add(message id); return newids; }); // add the new message to the messages state setmessages(prevmessages => { // check if the message is already in the list (additional duplicate check) if (prevmessages some(msg => msg id === message id)) { console log('message already in list, not adding again ', message id); return prevmessages; } return \[ prevmessages, newmessage]; }); // use the captured user to avoid null reference if (captureduser && message get('sender') id !== captureduser id) { setconversations(prevconversations => { return prevconversations map(conv => { if (conv id === conversationid) { return { conv, lastmessage message get('text'), updatedat message get('createdat') }; } return conv; }); }); } else { // if user check fails, update without the check setconversations(prevconversations => { return prevconversations map(conv => { if (conv id === conversationid) { return { conv, lastmessage message get('text'), updatedat message get('createdat') }; } return conv; }); }); } // scroll to bottom of messages settimeout(() => { if (messagesendref current) { messagesendref current scrollintoview({ behavior 'smooth' }); } }, 100); }); // handle errors livequerysubscription current on('error', (error) => { console error('live query error ', error); }); // handle subscription close livequerysubscription current on('close', () => { console log('live query connection closed for conversation ', conversationid); }); } catch (error) { console error('error setting up live query ', error); toaster create({ title 'error', description 'failed to set up real time messaging', type 'error', }); } }; การตั้งค่า live query นี้ สร้างการสมัครสมาชิกเพื่อรับข้อความใหม่ในสนทนาปัจจุบัน จัดการข้อความที่เข้ามาแบบเรียลไทม์ อัปเดต ui ด้วยข้อความใหม่เมื่อมีการเข้ามา อัปเดตรายการสนทนาด้วยข้อความล่าสุดและเวลาที่ส่ง จัดการข้อความที่ซ้ำกัน (ซึ่งอาจเกิดขึ้นเมื่อส่งและรับผ่าน live query) back4gram โครงการ ค้นหา ที่นี่ รหัสทั้งหมดสำหรับ โครงการตัวอย่างเครือข่ายสังคม ที่สร้างด้วย back4app ขั้นตอนที่ 7 – การนำเสนอการพิมพ์ตัวบ่งชี้ เพื่อปรับปรุงประสบการณ์ของผู้ใช้ มาลองเพิ่มตัวบ่งชี้การพิมพ์แบบเรียลไทม์กันเถอะ const setuptypingstatussubscription = async (conversationid) => { // cancel previous subscription, if it exists if (typingstatussubscription current) { typingstatussubscription current unsubscribe(); console log('unsubscribed from previous typing status subscription'); } try { console log('setting up typing status subscription for conversation ', conversationid); // create a query for the typingstatus class const query = new parse query('typingstatus'); const conversation = new parse object('conversation'); conversation id = conversationid; // filter by conversation query equalto('conversation', conversation); // don't include the current user's status query notequalto('user', currentuser); // subscribe to the query typingstatussubscription current = await query subscribe(); console log('successfully subscribed to typing status'); // handle create events typingstatussubscription current on('create', (status) => { console log('typing status created ', status get('istyping')); setotherusertyping(status get('istyping')); }); // handle update events typingstatussubscription current on('update', (status) => { console log('typing status updated ', status get('istyping')); setotherusertyping(status get('istyping')); }); // handle errors typingstatussubscription current on('error', (error) => { console error('typing status subscription error ', error); }); } catch (error) { console error('error setting up typing status subscription ', error); } }; const updatetypingstatus = async (istyping) => { if (!activeconversation || !currentuser) return; try { // check if a typing status already exists for this user and conversation const query = new parse query('typingstatus'); const conversation = new parse object('conversation'); conversation id = activeconversation id; query equalto('user', currentuser); query equalto('conversation', conversation); const existingstatus = await query first(); if (existingstatus) { // update existing status existingstatus set('istyping', istyping); await existingstatus save(); } else { // create a new status const typingstatus = parse object extend('typingstatus'); const newstatus = new typingstatus(); newstatus set('user', currentuser); newstatus set('conversation', conversation); newstatus set('istyping', istyping); await newstatus save(); } } catch (error) { console error('error updating typing status ', error); } }; การดำเนินการนี้ สมัครรับการอัปเดตสถานะการพิมพ์จากผู้ใช้คนอื่นในสนทนา อัปเดต ui เมื่อมีคนอื่นกำลังพิมพ์ ส่งการอัปเดตสถานะการพิมพ์เมื่อผู้ใช้ปัจจุบันกำลังพิมพ์ back4gram project ค้นหา ที่นี่ รหัสทั้งหมดสำหรับ โครงการตัวอย่างเครือข่ายสังคม ที่สร้างด้วย back4app ขั้นตอนที่ 8 – การส่งข้อความ ตอนนี้เรามา implement ฟังก์ชันการส่งข้อความกันเถอะ const sendmessage = async () => { if (!message trim() || !activeconversation) return; const messagetext = message trim(); // store the message text setissending(true); setmessage(''); // clear input immediately to prevent double sending setistyping(false); // clear typing status locally updatetypingstatus(false); // clear typing status on server // clear typing timer if (typingtimerref current) { cleartimeout(typingtimerref current); } try { // create message const message = parse object extend('message'); const newmessage = new message(); // set conversation pointer const conversation = new parse object('conversation'); conversation id = activeconversation id; newmessage set('conversation', conversation); newmessage set('sender', currentuser); newmessage set('text', messagetext); // save the message const savedmessage = await newmessage save(); console log('message saved ', savedmessage id); // add the message id to the set of processed ids to prevent duplication // when it comes back through live query setprocessedmessageids(previds => { const newids = new set(previds); newids add(savedmessage id); return newids; }); // check if this is a new conversation (no messages yet) // if it is, add the message to the ui immediately if (messages length === 0) { console log('first message in conversation, adding to ui immediately'); const formattedmessage = { id savedmessage id, text messagetext, sender { id currentuser id, username currentuser get('username') }, createdat new date() }; setmessages(\[formattedmessage]); // scroll to bottom of messages settimeout(() => { if (messagesendref current) { messagesendref current scrollintoview({ behavior 'smooth' }); } }, 100); } // update conversation's lastmessage const conversationobj = await new parse query('conversation') get(activeconversation id); conversationobj set('lastmessage', messagetext); await conversationobj save(); // update the conversation in the list setconversations(prevconversations => { return prevconversations map(conv => { if (conv id === activeconversation id) { return { conv, lastmessage messagetext, updatedat new date() }; } return conv; }); }); } catch (error) { console error('error sending message ', error); toaster create({ title 'error', description 'failed to send message', type 'error', }); // if there's an error, put the message back in the input setmessage(messagetext); } finally { setissending(false); } }; ฟังก์ชันนี้ สร้างและบันทึกข้อความใหม่ในฐานข้อมูล back4app อัปเดตข้อความล่าสุดและเวลาของการสนทนา จัดการการป้องกันการซ้ำเมื่อข้อความกลับมาผ่าน live query ให้ข้อเสนอแนะแก่ผู้ส่งทันที โครงการ back4gram ค้นหา ที่นี่ โค้ดทั้งหมดสำหรับ โครงการตัวอย่างเครือข่ายสังคม ที่สร้างด้วย back4app ขั้นตอนที่ 9 – การค้นหาผู้ใช้และเริ่มการสนทนาใหม่ มาดำเนินการเพิ่มความสามารถในการค้นหาผู้ใช้และเริ่มการสนทนาใหม่กันเถอะ const searchusers = async (query) => { if (!query trim()) { setusers(\[]); return; } try { console log('searching for users with query ', query); // create a query for the user class const userquery = new parse query(parse user); // search for username containing the query string (case insensitive) userquery contains('username', query tolowercase()); // don't include the current user in results userquery notequalto('objectid', currentuser id); // limit to 10 results userquery limit(10); // execute the query const results = await userquery find(); console log('user search results ', results length); // format users const formattedusers = results map(user => ({ id user id, username user get('username'), avatar user get('avatar') ? user get('avatar') url() null })); console log('formatted users ', formattedusers); setusers(formattedusers); } catch (error) { console error('error searching users ', error); toaster create({ title 'error', description 'failed to search users', type 'error', }); } }; const startconversation = async (userid) => { console log('starting conversation with user id ', userid); try { // check if a conversation already exists with this user const query = new parse query('conversation'); // create pointers to both users const currentuserpointer = parse user current(); const otheruserpointer = new parse user(); otheruserpointer id = userid; // find conversations where both users are participants query containsall('participants', \[currentuserpointer, otheruserpointer]); const existingconv = await query first(); if (existingconv) { console log('found existing conversation ', existingconv id); // get the other user object const userquery = new parse query(parse user); const otheruser = await userquery get(userid); // format the conversation const conversation = { id existingconv id, user { id otheruser id, username otheruser get('username'), avatar otheruser get('avatar') ? otheruser get('avatar') url() null }, lastmessage existingconv get('lastmessage') || '', updatedat existingconv get('updatedat') }; // set as active conversation setactiveconversation(conversation); // fetch messages and set up live query await fetchmessages(conversation id); } else { console log('creating new conversation with user ', userid); // get the other user object const userquery = new parse query(parse user); const otheruser = await userquery get(userid); // create a new conversation const conversation = parse object extend('conversation'); const newconversation = new conversation(); // set participants newconversation set('participants', \[currentuserpointer, otheruserpointer]); newconversation set('lastmessage', ''); // save the conversation const savedconv = await newconversation save(); console log('new conversation created ', savedconv id); // format the conversation const conversation = { id savedconv id, user { id otheruser id, username otheruser get('username'), avatar otheruser get('avatar') ? otheruser get('avatar') url() null }, lastmessage '', updatedat savedconv get('updatedat') }; // add to conversations list setconversations(prev => \[conversation, prev]); // set as active conversation and reset message state setactiveconversation(conversation); resetmessagestate(); // set up live query for the new conversation await setuplivequery(savedconv id); // set up typing status subscription await setuptypingstatussubscription(savedconv id); // reset search setshowusersearch(false); setsearchquery(''); setusers(\[]); } } catch (error) { console error('error starting conversation ', error); toaster create({ title 'error', description 'failed to start conversation', type 'error', }); } }; รหัสนี้มีฟังก์ชันที่สำคัญสองอย่างสำหรับระบบการส่งข้อความของเรา การค้นหาผู้ใช้ ฟังก์ชัน searchusers ช่วยให้ผู้ใช้สามารถค้นหาผู้ใช้อื่นโดยใช้ชื่อผู้ใช้ มันจะทำการค้นหาคลาสผู้ใช้ใน back4app ยกเว้นผู้ใช้ปัจจุบันจากผลลัพธ์ และจัดรูปแบบข้อมูลเพื่อแสดงผล การสร้างการสนทนา ฟังก์ชัน startconversation จัดการทั้งการค้นหาการสนทนาที่มีอยู่และการสร้างการสนทนาใหม่ มัน ตรวจสอบว่ามีการสนทนาอยู่ระหว่างผู้ใช้หรือไม่ ถ้ามี มันจะโหลดการสนทนานั้นและข้อความของมัน ถ้าไม่มีการสนทนา มันจะสร้างการสนทนาใหม่ ตั้งค่าการสมัครสมาชิก live query สำหรับข้อความใหม่และสถานะการพิมพ์ เมื่อฟังก์ชันเหล่านี้ถูกนำไปใช้ ผู้ใช้สามารถค้นหาผู้ใช้อื่นและเริ่มการสนทนากับพวกเขาได้อย่างง่ายดาย ซึ่งเป็นสิ่งสำคัญสำหรับระบบการส่งข้อความในเครือข่ายสังคม โครงการ back4gram ค้นหา ที่นี่ โค้ดทั้งหมดสำหรับ โครงการตัวอย่างเครือข่ายสังคม ที่สร้างด้วย back4app ขั้นตอนที่ 10 – การสร้าง ui แชท ตอนนี้ที่เราได้ดำเนินการฟังก์ชันการทำงานทั้งหมดแล้ว มาสร้างส่วนติดต่อผู้ใช้สำหรับระบบการส่งข้อความของเรากัน ส่วนติดต่อผู้ใช้จะประกอบด้วย รายการด้านข้างที่แสดงการสนทนาทั้งหมด อินเทอร์เฟซการค้นหาเพื่อค้นหาผู้ใช้ หน้าต่างแชทที่แสดงข้อความ ช่องป้อนข้อความที่รองรับการแสดงสถานะการพิมพ์ นี่คือ jsx สำหรับคอมโพเนนต์ messagespage ของเรา return ( \<flex h="100vh"> {/ chat list sidebar /} \<box w="300px" borderrightwidth="1px" bordercolor="gray 600" p={4} bg="gray 800"> \<heading size="md" mb={4}> messages \</heading> \<flex mb={4}> \<input placeholder="search users " value={searchquery} onchange={(e) => { const value = e target value; setsearchquery(value); if (value trim() length > 0) { searchusers(value); } else { setusers(\[]); } }} mr={2} /> \<button onclick={() => { setshowusersearch(!showusersearch); if (!showusersearch) { setsearchquery(''); setusers(\[]); } }} \> {showusersearch ? 'cancel' 'new'} \</button> \</flex> {isloading ? ( \<center py={10}> \<spinner size="lg" /> \</center> ) showusersearch ? ( // user search results \<vstack align="stretch" spacing={2}> {users length > 0 ? ( users map(user => ( \<box key={user id} p={3} borderradius="md" hover={{ bg "gray 700" }} cursor="pointer" onclick={() => startconversation(user id)} \> \<hstack> \<avatar size="sm" name={user username} src={user avatar} /> \<text>{user username}\</text> \</hstack> \</box> )) ) searchquery ? ( \<text color="gray 400" textalign="center">no users found\</text> ) ( \<text color="gray 400" textalign="center">search for users to message\</text> )} \</vstack> ) ( // conversations list \<vstack align="stretch" spacing={0}> {conversations length > 0 ? ( conversations map(conv => ( \<box key={conv id} p={3} borderradius="md" bg={activeconversation? id === conv id ? "gray 700" "transparent"} hover={{ bg "gray 700" }} cursor="pointer" onclick={() => { if (activeconversation? id !== conv id) { setactiveconversation(conv); fetchmessages(conv id); } }} \> \<hstack> \<avatar size="sm" name={conv user username} src={conv user avatar} /> \<box flex="1" overflow="hidden"> \<flex justify="space between" align="center"> \<text fontweight="bold" nooflines={1}>{conv user username}\</text> \<text fontsize="xs" color="gray 400"> {formatconversationdate(conv updatedat)} \</text> \</flex> \<text fontsize="sm" color="gray 400" nooflines={1}> {conv lastmessage || 'no messages yet'} \</text> \</box> \</hstack> \</box> )) ) ( \<text color="gray 400" textalign="center" mt={8}> no conversations yet start a new one! \</text> )} \</vstack> )} \</box> {/ chat window /} \<box flex={1} p={0} display="flex" flexdirection="column" bg="gray 900"> {activeconversation ? ( <> {/ chat header /} \<flex align="center" p={4} borderbottomwidth="1px" bordercolor="gray 700"> \<avatar size="sm" mr={2} name={activeconversation user username} src={activeconversation user avatar} /> \<text fontweight="bold">{activeconversation user username}\</text> {otherusertyping && ( \<text ml={2} color="gray 400" fontsize="sm"> is typing \</text> )} \</flex> {/ messages /} \<box flex={1} p={4} overflowy="auto" display="flex" flexdirection="column" \> {messages length > 0 ? ( messages map((msg) => ( \<box key={msg id} alignself={msg sender id === currentuser id ? "flex end" "flex start"} bg={msg sender id === currentuser id ? "blue 500" "gray 700"} color={msg sender id === currentuser id ? "white" "white"} p={3} borderradius="lg" maxw="70%" mb={2} \> \<text>{msg text}\</text> \<text fontsize="xs" color={msg sender id === currentuser id ? "blue 100" "gray 400"} textalign="right" mt={1}> {formatmessagetime(msg createdat)} \</text> \</box> )) ) ( \<center flex={1}> \<text color="gray 400"> no messages yet say hello! \</text> \</center> )} \<div ref={messagesendref} /> \</box> {/ message input /} \<flex p={4} bordertopwidth="1px" bordercolor="gray 700"> \<input placeholder="type a message " value={message} onchange={(e) => { setmessage(e target value); // set typing status to true locally setistyping(true); // update typing status on server updatetypingstatus(true); // clear any existing timer if (typingtimerref current) { cleartimeout(typingtimerref current); } // set a new timer to turn off typing status after 2 seconds of inactivity typingtimerref current = settimeout(() => { setistyping(false); updatetypingstatus(false); }, 2000); }} mr={2} onkeypress={(e) => { if (e key === 'enter' && !e shiftkey) { e preventdefault(); sendmessage(); // also clear typing status when sending a message setistyping(false); updatetypingstatus(false); if (typingtimerref current) { cleartimeout(typingtimerref current); } } }} /> \<button colorscheme="blue" onclick={sendmessage} isloading={issending} disabled={!message trim() || issending} \> send \</button> \</flex> \</> ) ( \<center flex={1}> \<vstack> \<text fontsize="xl" fontweight="bold">welcome to messages\</text> \<text color="gray 400"> select a conversation or start a new one \</text> \</vstack> \</center> )} \</box> \</flex> ); เรามาแยก ui ออกเป็นส่วนประกอบหลักกันเถอะ แถบด้านข้างการสนทนา แถบด้านซ้ายแสดงรายการการสนทนาทั้งหมด แต่ละการสนทนาจะแสดงชื่อผู้ใช้คนอื่น อวตาร และข้อความล่าสุด ผู้ใช้สามารถคลิกที่การสนทนาใดก็ได้เพื่อดูและดำเนินการสนทนาต่อ แถบค้นหาที่ด้านบนช่วยให้ค้นหาผู้ใช้อื่นเพื่อเริ่มการสนทนาใหม่ การแสดงข้อความ พื้นที่หลักแสดงข้อความสำหรับการสนทนาที่ใช้งานอยู่ ข้อความจากผู้ใช้ปัจจุบันจะแสดงทางด้านขวาพร้อมพื้นหลังสีน้ำเงิน ข้อความจากผู้ใช้อื่นจะแสดงทางด้านซ้ายพร้อมพื้นหลังสีเทา แต่ละข้อความจะแสดงข้อความและเวลาที่ส่ง รายการข้อความจะเลื่อนอัตโนมัติไปที่ด้านล่างเมื่อมีข้อความใหม่เข้ามา การป้อนข้อความ ที่ด้านล่างเป็นพื้นที่ป้อนข้อความเพื่อพิมพ์และส่งข้อความ ผู้ใช้สามารถกด enter เพื่อส่งข้อความ ปุ่มส่งยังช่วยให้ส่งข้อความได้ การพิมพ์ในพื้นที่ป้อนข้อความจะกระตุ้นตัวบ่งชี้การพิมพ์โดยอัตโนมัติ การป้อนข้อมูลจะถูกปิดใช้งานจนกว่าจะมีการเลือกการสนทนา ตัวบ่งชี้การพิมพ์ เมื่อผู้ใช้คนอื่นกำลังพิมพ์ ตัวบ่งชี้ "กำลังพิมพ์ " จะปรากฏขึ้น ตัวบ่งชี้จะถูกอัปเดตแบบเรียลไทม์โดยใช้การสมัครสมาชิก typingstatus live query ui นี้ให้การแสดงผลที่สะอาดและใช้งานง่ายสำหรับการส่งข้อความ คล้ายกับสิ่งที่ผู้ใช้คาดหวังจากแอปพลิเคชันส่งข้อความยอดนิยม โครงการ back4gram ค้นหา ที่นี่ โค้ดทั้งหมดสำหรับ โครงการตัวอย่างเครือข่ายสังคม ที่สร้างด้วย back4app ขั้นตอนที่ 11 – การทดสอบการเชื่อมต่อ live query เพื่อให้แน่ใจว่าการเชื่อมต่อ live query ของเราทำงานได้อย่างถูกต้อง มาลองเพิ่มฟังก์ชันทดสอบที่ตรวจสอบการเชื่อมต่อเมื่อคอมโพเนนต์ถูกติดตั้ง // add this at the beginning of the component to test live query connection useeffect(() => { // test live query connection const testlivequery = async () => { try { console log('testing live query connection '); console log('live query url ', parse livequeryserverurl); const query = new parse query('message'); console log('created test query for message class'); const subscription = await query subscribe(); console log('live query subscription successful!'); subscription on('open', () => { console log('live query connection opened successfully'); }); subscription on('create', (object) => { console log('live query create event received ', object id); }); subscription on('error', (error) => { console error('live query error ', error); }); // unsubscribe after a few seconds to test settimeout(() => { subscription unsubscribe(); console log('unsubscribed from test live query'); }, 10000); } catch (error) { console error('error testing live query ', error); } }; testlivequery(); }, \[]); ฟังก์ชันทดสอบนี้ พยายามสร้างการสมัครสมาชิกสำหรับคลาส message ตั้งค่าตัวจัดการเหตุการณ์สำหรับเหตุการณ์การเชื่อมต่อ บันทึกผลลัพธ์ของแต่ละขั้นตอน ยกเลิกการสมัครสมาชิกโดยอัตโนมัติหลังจาก 10 วินาที โดยการดูบันทึกในคอนโซล คุณสามารถตรวจสอบได้ว่า url ของ live query ถูกกำหนดค่าอย่างถูกต้อง สามารถเชื่อมต่อได้ เหตุการณ์ถูกส่งมาอย่างถูกต้อง หากคุณพบปัญหาใด ๆ กับการเชื่อมต่อ live query ให้ตรวจสอบสิ่งต่อไปนี้ back4app live query ถูกเปิดใช้งานสำหรับแอปของคุณ url ของ live query ถูกตั้งค่าอย่างถูกต้องในขั้นตอนการเริ่มต้น parse ของคุณ คลาส message ถูกเพิ่มลงในรายการคลาส live query ใน back4app เครือข่ายของคุณอนุญาตการเชื่อมต่อ websocket โครงการ back4gram ค้นหา ที่นี่ โค้ดทั้งหมดสำหรับ โครงการตัวอย่างเครือข่ายสังคม ที่สร้างขึ้นด้วย back4app ขั้นตอนที่ 12 – เข้าใจว่า back4app เปิดใช้งานการส่งข้อความแบบเรียลไทม์อย่างไร ตอนนี้ที่เราได้สร้างระบบการส่งข้อความที่สมบูรณ์แล้ว มาดูอย่างลึกซึ้งว่าฟีเจอร์ของ back4app ทำให้การส่งข้อความแบบเรียลไทม์เป็นไปได้อย่างไร โครงสร้างการค้นหาสด ฟีเจอร์ live query ของ back4app สร้างขึ้นบน websockets ซึ่งให้การเชื่อมต่อที่ต่อเนื่องระหว่างไคลเอนต์และเซิร์ฟเวอร์ นี่แตกต่างจากโมเดลการร้องขอ/การตอบสนองแบบ http แบบดั้งเดิมอย่างสิ้นเชิง rest api แบบดั้งเดิม ไคลเอนต์ทำการร้องขอ → เซิร์ฟเวอร์ตอบสนอง → การเชื่อมต่อปิด websockets/live query ไคลเอนต์สร้างการเชื่อมต่อที่ต่อเนื่อง → เซิร์ฟเวอร์สามารถส่งการอัปเดตได้ตลอดเวลา การเชื่อมต่อที่ต่อเนื่องนี้คือสิ่งที่ทำให้ความสามารถในการทำงานแบบเรียลไทม์ในระบบการส่งข้อความของเราเป็นไปได้ เมื่อมีการสร้างข้อความใหม่ back4app จะส่งการอัปเดตนั้นไปยังไคลเอนต์ที่สมัครสมาชิกทั้งหมดโดยอัตโนมัติโดยที่พวกเขาไม่ต้องทำการตรวจสอบเซิร์ฟเวอร์ โมเดลการสมัครสมาชิกของ parse server โมเดลการสมัครสมาชิกใน parse server เป็นแบบการค้นหา ซึ่งหมายความว่า คุณสมัครสมาชิกกับการค้นหาเฉพาะ (เช่น "ข้อความทั้งหมดในสนทนา x") คุณจะได้รับการอัปเดตเฉพาะสำหรับวัตถุที่ตรงกับการค้นหานั้น คุณสามารถรับเหตุการณ์ประเภทต่างๆ ( สร้าง , อัปเดต , ลบ , ฯลฯ) วิธีการที่ใช้การค้นหานี้มีพลังมากเพราะช่วยให้สามารถสมัครสมาชิกได้อย่างแม่นยำ ในระบบการส่งข้อความของเรา เรากำลังสมัครสมาชิกเฉพาะข้อความสำหรับการสนทนาที่ใช้งานอยู่ ซึ่งมีประสิทธิภาพมากกว่าการสมัครสมาชิกข้อความทั้งหมด ข้อพิจารณาเกี่ยวกับฐานข้อมูล เมื่อใช้ live query กับ back4app มีข้อพิจารณาที่สำคัญเกี่ยวกับฐานข้อมูลบางประการ การจัดทำดัชนี ตรวจสอบให้แน่ใจว่าฟิลด์ที่ใช้ในคำถามการสมัครสมาชิกได้รับการจัดทำดัชนีเพื่อประสิทธิภาพที่ดีกว่า ขนาดข้อมูล รักษาวัตถุให้มีขนาดเล็กเพื่อลดขนาดข้อมูลที่ส่งและปรับปรุงประสิทธิภาพ การปรับขนาด การเชื่อมต่อ live query ใช้ทรัพยากร ดังนั้นควรพิจารณานี้เมื่อปรับขนาดแอปพลิเคชันของคุณ เพื่อประสิทธิภาพที่ดีที่สุด ควรพิจารณา การสร้างดัชนีใน การสนทนา ฟิลด์ในคลาสข้อความ การใช้พอยเตอร์แทนการฝังวัตถุขนาดใหญ่ การจัดการวงจรชีวิตของการสมัครสมาชิกเพื่อหลีกเลี่ยงการรั่วไหลของหน่วยความจำ การพิจารณาด้านความปลอดภัย เมื่อดำเนินการส่งข้อความแบบเรียลไทม์ ความปลอดภัยเป็นสิ่งสำคัญ acls และ clps ใช้ access control lists และ class level permissions เพื่อปกป้องข้อมูลของคุณ การตรวจสอบการเชื่อมต่อ ผู้ใช้ที่ได้รับการตรวจสอบเท่านั้นที่ควรสามารถสร้างการเชื่อมต่อ live query ได้ การตรวจสอบข้อมูล ตรวจสอบเนื้อหาข้อความที่ฝั่งเซิร์ฟเวอร์โดยใช้ cloud code การจำกัดอัตรา ใช้การจำกัดอัตราเพื่อป้องกันการใช้ประโยชน์ ตัวอย่างเช่น คุณอาจต้องการใช้ cloud code เพื่อตรวจสอบและทำความสะอาดข้อความก่อนที่จะถูกบันทึก // in cloud code parse cloud beforesave("message", async (request) => { const message = request object; const text = message get("text"); // check if message is empty if (!text || text trim() length === 0) { throw new error("message cannot be empty"); } // sanitize message text message set("text", sanitizehtml(text)); // rate limiting check if user is sending too many messages const sender = message get("sender"); const query = new parse query("message"); query equalto("sender", sender); query greaterthan("createdat", new date(new date() 60000)); // last minute const count = await query count({usemasterkey true}); if (count > 10) { throw new error("you are sending messages too quickly please slow down "); } }); back4gram project ค้นหา ที่นี่ โค้ดทั้งหมดสำหรับ โปรเจกต์ตัวอย่าง social network ที่สร้างด้วย back4app ขั้นตอนที่ 13 – การทดสอบและการปรับแต่งระบบการส่งข้อความ เพื่อให้ระบบการส่งข้อความของคุณทำงานได้อย่างถูกต้อง คุณควรทดสอบอย่างละเอียด unhandled content type การทดสอบฟังก์ชันพื้นฐาน การส่งข้อความ ยืนยันว่าข้อความสามารถส่งและรับได้ การสร้างการสนทนา ทดสอบการสร้างการสนทนาใหม่ การค้นหาผู้ใช้ ยืนยันว่าผู้ใช้สามารถค้นหาได้และเริ่มการสนทนาได้ การอัปเดต ui ตรวจสอบว่าตัวบ่งชี้การพิมพ์ รายการข้อความ และรายการการสนทนาถูกอัปเดตอย่างถูกต้อง การทดสอบหลายผู้ใช้ เพื่อทดสอบระบบการส่งข้อความอย่างถูกต้อง คุณต้องทดสอบกับผู้ใช้หลายคน เปิดหน้าต่างหรือแท็บเบราว์เซอร์สองอัน เข้าสู่ระบบในฐานะผู้ใช้ที่แตกต่างกันในแต่ละอัน เริ่มการสนทนาระหว่างพวกเขา ส่งข้อความไปมา ทดสอบตัวบ่งชี้การพิมพ์และการอัปเดตแบบเรียลไทม์ การเพิ่มประสิทธิภาพการทำงาน สำหรับแอปพลิเคชันขนาดใหญ่ ให้พิจารณาการเพิ่มประสิทธิภาพเหล่านี้ การแบ่งหน้า โหลดข้อความเป็นกลุ่มแทนที่จะโหลดทั้งหมดในครั้งเดียว การจัดการการเชื่อมต่อ สร้างการเชื่อมต่อ live query สำหรับการสนทนาที่ใช้งานอยู่เท่านั้น การค้นหาที่มีประสิทธิภาพ ใช้การค้นหาที่มีเป้าหมายและรวมเฉพาะฟิลด์ที่จำเป็น การแคช ใช้การแคชฝั่งไคลเอ็นต์สำหรับข้อมูลที่เข้าถึงบ่อย นี่คือตัวอย่างการใช้การแบ่งหน้าในการโหลดข้อความ const fetchmessages = async (conversationid, limit = 20, skip = 0) => { try { const query = new parse query('message'); const conversation = new parse object('conversation'); conversation id = conversationid; query equalto('conversation', conversation); query include('sender'); query descending('createdat'); query limit(limit); query skip(skip); const results = await query find(); // process results return { messages formattedmessages, hasmore results length === limit }; } catch (error) { console error('error fetching messages ', error); throw error; } }; การจัดการข้อผิดพลาดและการกู้คืน การจัดการข้อผิดพลาดที่แข็งแกร่งเป็นสิ่งสำคัญสำหรับแอปพลิเคชันเรียลไทม์ การล้มเหลวในการเชื่อมต่อ ใช้ตรรกะการเชื่อมต่อใหม่สำหรับการล้มเหลวของ websocket การล้มเหลวของข้อความ จัดการการส่งข้อความที่ล้มเหลวและให้ตัวเลือกในการลองใหม่ การกู้คืนสถานะ กู้คืนสถานะของแอปพลิเคชันหลังจากการหยุดชะงักของการเชื่อมต่อ ตัวอย่างเช่น คุณอาจเพิ่มการตรวจสอบการเชื่อมต่อ // monitor live query connection status parse livequery on('open', () => { console log('live query connection established'); // re establish subscriptions if needed }); parse livequery on('close', () => { console log('live query connection closed'); // show connection status to user }); parse livequery on('error', (error) => { console error('live query error ', error); // handle error, potentially reconnect }); บทสรุป ในบทเรียนนี้ คุณได้สร้างระบบการส่งข้อความแบบเรียลไทม์ที่ครอบคลุมสำหรับเครือข่ายสังคมของคุณโดยใช้ back4app คุณได้ดำเนินการดังนี้ การส่งข้อความระหว่างผู้ใช้ สร้างระบบที่ผู้ใช้สามารถค้นหาและส่งข้อความถึงกันได้ การอัปเดตแบบเรียลไทม์ ใช้ live query ของ back4app เพื่อส่งข้อความทันที ตัวบ่งชี้การพิมพ์ ปรับปรุงประสบการณ์ผู้ใช้ด้วยการแจ้งเตือนการพิมพ์แบบเรียลไทม์ การจัดการการสนทนา สร้าง ui สำหรับการดูและจัดการการสนทนาหลายรายการ ฟีเจอร์ live query ของ back4app ให้โครงสร้างพื้นฐานแบบเรียลไทม์ที่จำเป็นในการทำให้สิ่งนี้เป็นไปได้โดยไม่ต้องจัดการเซิร์ฟเวอร์ websocket ที่ซับซ้อนหรือปัญหาการขยายตัว โดยการใช้โมเดลการสมัครสมาชิกที่สร้างไว้ใน parse server คุณจึงสามารถสร้างระบบการส่งข้อความที่ตอบสนองและมีประสิทธิภาพได้ ระบบการส่งข้อความที่คุณสร้างขึ้นให้พื้นฐานที่มั่นคงซึ่งคุณสามารถปรับปรุงด้วยฟีเจอร์เพิ่มเติม ขั้นตอนถัดไป ใบเสร็จรับเงินอ่าน นำระบบติดตามสถานะการอ่านข้อความมาใช้ การสนทนากลุ่ม ขยายระบบเพื่อรองรับผู้เข้าร่วมหลายคน การแชร์สื่อ เพิ่มการรองรับสำหรับภาพ วิดีโอ และไฟล์แนบอื่นๆ การตอบสนองข้อความ อนุญาตให้ผู้ใช้ตอบสนองต่อข้อความด้วยอีโมจิ การลบข้อความ นำความสามารถในการลบหรือแก้ไขข้อความมาใช้ การค้นหาขั้นสูง เพิ่มความสามารถในการค้นหาในบทสนทนา สำหรับรหัสทั้งหมดของแอปพลิเคชันเครือข่ายสังคม back4gram รวมถึงระบบการส่งข้อความ คุณสามารถตรวจสอบได้ที่ ที่เก็บ github https //github com/templates back4app/back4gram การรวมกันของฐานข้อมูล, api, ฟังก์ชันคลาวด์, การจัดเก็บไฟล์, การจัดการผู้ใช้ และความสามารถแบบเรียลไทม์ของ back4app ทำให้มันเป็นตัวเลือกที่ยอดเยี่ยมสำหรับการสร้างแอปพลิเคชันเครือข่ายสังคมที่มีฟีเจอร์ครบถ้วน โดยการใช้ back4app คุณสามารถมุ่งเน้นไปที่การสร้างประสบการณ์ผู้ใช้ที่ยอดเยี่ยมแทนที่จะต้องจัดการโครงสร้างพื้นฐานด้านหลังที่ซับซ้อน