Project Templates
Social Network
Obrolan Waktu Nyata untuk Jaringan Sosial Anda
53 mnt
pendahuluan dalam tutorial ini, anda akan belajar bagaimana mengimplementasikan sistem pesan waktu nyata untuk aplikasi jejaring sosial anda menggunakan back4app anda akan membangun fungsionalitas obrolan lengkap yang memungkinkan pengguna untuk mengirim dan menerima pesan secara instan, melihat indikator pengetikan, dan mengelola percakapan fitur penting untuk platform sosial yang menarik back4app adalah platform backend as a service (baas) yang dibangun di atas parse server yang menyediakan kemampuan waktu nyata yang kuat melalui fitur live query nya dengan infrastruktur waktu nyata back4app, anda dapat membuat sistem pesan responsif tanpa mengelola server websocket yang kompleks atau masalah penskalaan pada akhir tutorial ini, anda akan telah membuat sistem pesan yang sepenuhnya fungsional mirip dengan yang digunakan di back4gram, sebuah aplikasi jejaring sosial anda akan mengimplementasikan pembuatan percakapan, pertukaran pesan waktu nyata, indikator pengetikan, dan pencarian pengguna, memberikan pengalaman komunikasi yang mulus bagi pengguna anda proyek back4gram temukan di sini kode lengkap untuk sebuah proyek contoh jaringan sosial yang dibangun dengan back4app prasyarat untuk menyelesaikan tutorial ini, anda akan membutuhkan akun back4app anda dapat mendaftar untuk akun gratis di back4app com https //www back4app com proyek back4app yang sudah diatur dengan parse javascript sdk yang diinisialisasi node js terinstal di mesin lokal anda pengetahuan dasar tentang javascript, react js, dan back4app/parse server sistem otentikasi yang sudah diimplementasikan jika anda belum mengatur ini, lihat tutorial sistem otentikasi https //www back4app com/docs/react/authentication tutorial keterampilan dengan react hooks dan siklus hidup komponen langkah 1 – memahami kemampuan real time back4app sebelum kita mulai coding, mari kita pahami bagaimana back4app memungkinkan fungsionalitas real time melalui fitur live query nya penjelasan live query live query adalah fitur dari parse server yang memungkinkan klien untuk berlangganan pada kueri dan menerima pembaruan ketika objek yang cocok dengan kueri tersebut dibuat, diperbarui, atau dihapus ini sempurna untuk membangun aplikasi real time seperti sistem chat berikut adalah cara kerja live query klien berlangganan pada kueri tertentu (misalnya, "semua pesan dalam percakapan x") ketika objek yang cocok dibuat, diperbarui, atau dihapus di server live query secara otomatis memberi tahu semua klien yang berlangganan klien kemudian dapat memperbarui ui mereka sebagai respons terhadap peristiwa ini dalam konteks sistem pesan, ini berarti ketika pesan baru dikirim, semua pengguna dalam percakapan itu menerimanya secara instan ketika seorang pengguna mulai mengetik, pengguna lain dapat melihat indikator mengetik secara real time ketika pesan dibaca, tanda terima baca dapat diperbarui untuk semua peserta mengatur live query di back4app untuk menggunakan live query, anda perlu mengaktifkannya di dasbor back4app anda masuk ke dasbor back4app anda navigasikan ke pengaturan server > hosting web dan live query aktifkan live query tambahkan kelas yang ingin anda gunakan dengan live query (dalam kasus kami, "pesan" dan "statusmengetik") selanjutnya, dalam kode sisi klien anda, anda perlu menginisialisasi klien 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"; sekarang mari kita lanjutkan untuk merancang skema basis data kita untuk sistem pesan proyek back4gram temukan di sini kode lengkap untuk sebuah proyek contoh jaringan sosial yang dibangun dengan back4app langkah 2 – merancang skema basis data untuk sistem pesan kita, kita akan membutuhkan beberapa kelas parse percakapan mewakili obrolan antara dua atau lebih pengguna pesan mewakili pesan individu dalam sebuah percakapan statusmengetik melacak ketika pengguna sedang mengetik dalam sebuah percakapan mari kita buat kelas kelas ini di back4app kelas percakapan kelas percakapan akan memiliki bidang berikut peserta (array of pointers to user) pengguna yang terlibat dalam percakapan pesanterakhir (string) teks dari pesan terbaru diperbaruipada (tanggal) secara otomatis diperbarui oleh parse saat catatan berubah kelas pesan kelas pesan akan memiliki percakapan (pointer to conversation) percakapan yang dimiliki pesan ini pengirim (pointer to user) pengguna yang mengirim pesan teks (string) konten dari pesan dibuatpada (tanggal) secara otomatis dibuat oleh parse saat pesan dikirim kelas typingstatus kelas typingstatus akan melacak indikator pengetikan pengguna (pointer ke pengguna) pengguna yang sedang mengetik percakapan (pointer ke percakapan) percakapan di mana pengetikan terjadi sedangmengetik (boolean) apakah pengguna saat ini sedang mengetik sekarang, mari kita atur struktur proyek kita untuk mengimplementasikan sistem pesan ini proyek back4gram temukan di sini kode lengkap untuk sebuah proyek contoh jaringan sosial yang dibangun dengan back4app langkah 3 – menyiapkan struktur proyek mari kita atur kode kita untuk sistem pesan kita akan fokus pada komponen yang penting src/ ├── components/ │ └── ui/ │ ├── toaster js │ └── avatar js ├── pages/ │ └── messagespage js ├── app js └── parseconfig js mari kita buat sebuah toaster js untuk notifikasi // 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}`); } }; dan perbarui app js kita untuk menyertakan rute pesan // 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; sekarang, mari kita terapkan fungsionalitas pesan utama proyek back4gram temukan di sini kode lengkap untuk sebuah proyek contoh jaringan sosial yang dibangun dengan back4app langkah 4 – membuat komponen halaman pesan komponen messagespage js kita akan menjadi inti dari sistem pesan kita ini akan tampilkan daftar percakapan izinkan pengguna untuk melihat dan mengirim pesan tampilkan indikator mengetik aktifkan pencarian pengguna untuk memulai percakapan baru mari kita bangun ini langkah demi langkah // 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; sekarang mari kita implementasikan masing masing fungsi yang dibutuhkan untuk sistem pesan kita proyek back4gram temukan di sini kode lengkap untuk sebuah proyek contoh jaringan sosial yang dibangun dengan back4app langkah 5 – mengambil percakapan pengguna pertama, mari kita implementasikan fetchconversations fungsi yang memuat semua percakapan untuk pengguna saat ini 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); } }; fungsi ini mengkueri kelas percakapan untuk percakapan di mana pengguna saat ini adalah peserta memformat hasil untuk ditampilkan di ui menetapkan percakapan pertama sebagai aktif jika tersedia proyek back4gram temukan di sini kode lengkap untuk sebuah proyek contoh jaringan sosial yang dibangun dengan back4app langkah 6 – menangani pesan dan pembaruan waktu nyata sekarang mari kita implementasikan fungsi untuk mengambil pesan dan menyiapkan pembaruan waktu nyata menggunakan 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', }); } }; sekarang, mari kita implementasikan langganan live query untuk pembaruan pesan waktu nyata 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', }); } }; pengaturan query langsung ini membuat langganan untuk pesan baru dalam percakapan saat ini menangani pesan masuk secara real time memperbarui ui dengan pesan baru saat mereka tiba memperbarui daftar percakapan dengan pesan dan cap waktu terbaru mengelola pesan duplikat (yang dapat terjadi saat mengirim dan menerima melalui live query) proyek back4gram temukan di sini kode lengkap untuk sebuah proyek contoh jaringan sosial yang dibangun dengan back4app langkah 7 – menerapkan indikator pengetikan untuk meningkatkan pengalaman pengguna, mari kita tambahkan indikator pengetikan waktu nyata 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); } }; implementasi ini berlangganan pembaruan status pengetikan dari pengguna lain dalam percakapan memperbarui ui ketika orang lain sedang mengetik mengirim pembaruan status pengetikan ketika pengguna saat ini sedang mengetik proyek back4gram temukan di sini kode lengkap untuk sebuah proyek contoh jaringan sosial yang dibangun dengan back4app langkah 8 – mengirim pesan sekarang mari kita implementasikan fungsionalitas pengiriman pesan 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); } }; fungsi ini membuat dan menyimpan pesan baru di database back4app memperbarui pesan terakhir dan timestamp percakapan menangani pencegahan duplikat ketika pesan kembali melalui live query memberikan umpan balik langsung kepada pengirim proyek back4gram temukan di sini kode lengkap untuk sebuah proyek contoh jaringan sosial yang dibangun dengan back4app langkah 9 – pencarian pengguna dan memulai percakapan baru mari kita terapkan kemampuan untuk mencari pengguna dan memulai percakapan baru 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', }); } }; kode ini menyediakan dua fungsi penting untuk sistem pesan kami pencarian pengguna fungsi searchusers memungkinkan pengguna untuk menemukan pengguna lain berdasarkan nama pengguna ini melakukan kueri pada kelas pengguna di back4app, mengecualikan pengguna saat ini dari hasil, dan memformat data untuk ditampilkan pembuatan percakapan fungsi startconversation menangani baik pencarian percakapan yang ada maupun pembuatan yang baru ini memeriksa apakah percakapan sudah ada antara pengguna jika ada, itu memuat percakapan dan pesannya jika tidak ada percakapan yang ada, itu membuat yang baru menyiapkan langganan live query untuk pesan baru dan status mengetik dengan fungsi fungsi ini diterapkan, pengguna dapat dengan mudah menemukan pengguna lain dan memulai percakapan dengan mereka, yang sangat penting untuk sistem pesan jejaring sosial proyek back4gram temukan di sini kode lengkap untuk sebuah proyek contoh jejaring sosial yang dibangun dengan back4app langkah 10 – membangun antarmuka chat sekarang kita telah menerapkan semua fungsionalitas, mari kita buat antarmuka pengguna untuk sistem pesan kita antarmuka pengguna akan terdiri dari sebuah sidebar yang mencantumkan semua percakapan antarmuka pencarian untuk menemukan pengguna sebuah jendela obrolan yang menampilkan pesan sebuah input pesan dengan dukungan indikator pengetikan berikut adalah jsx untuk komponen messagespage kami 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> ); mari kita uraikan ui menjadi komponen utamanya sidebar percakapan sidebar kiri menunjukkan daftar semua percakapan setiap percakapan menunjukkan nama pengguna lain, avatar, dan pesan terakhir pengguna dapat mengklik percakapan mana pun untuk melihat dan melanjutkan obrolan bilah pencarian di bagian atas memungkinkan menemukan pengguna lain untuk memulai percakapan baru tampilan pesan area utama menampilkan pesan untuk percakapan aktif pesan dari pengguna saat ini muncul di sebelah kanan dengan latar belakang biru pesan dari pengguna lain muncul di sebelah kiri dengan latar belakang abu abu setiap pesan menunjukkan teks pesan dan waktu pengirimannya daftar pesan secara otomatis menggulir ke bawah saat pesan baru tiba input pesan di bagian bawah terdapat area input untuk mengetik dan mengirim pesan pengguna dapat menekan enter untuk mengirim pesan tombol kirim juga memungkinkan mengirim pesan mengetik di area input secara otomatis memicu indikator mengetik input dinonaktifkan sampai percakapan dipilih indikator pengetikan ketika pengguna lain sedang mengetik, indikator "sedang mengetik " muncul indikator diperbarui secara real time menggunakan langganan live query typingstatus antarmuka pengguna ini menyediakan antarmuka yang bersih dan intuitif untuk pesan, mirip dengan apa yang diharapkan pengguna dari aplikasi pesan populer proyek back4gram temukan di sini kode lengkap untuk sebuah proyek contoh jaringan sosial yang dibangun dengan back4app langkah 11 – menguji koneksi live query untuk memastikan bahwa koneksi live query kami berfungsi dengan baik, mari kita tambahkan fungsi uji yang memverifikasi koneksi saat komponen dipasang // 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(); }, \[]); fungsi uji ini mencoba membuat langganan ke kelas message mengatur penangan acara untuk acara koneksi mencatat hasil dari setiap langkah secara otomatis berhenti berlangganan setelah 10 detik dengan melihat log konsol, anda dapat memverifikasi bahwa url kuery langsung telah dikonfigurasi dengan benar koneksi dapat dibuat acara diterima dengan baik jika anda mengalami masalah dengan koneksi kuery langsung, periksa hal hal berikut kuery langsung back4app diaktifkan untuk aplikasi anda url kuery langsung telah diatur dengan benar dalam inisialisasi parse anda kelas pesan telah ditambahkan ke daftar kelas kuery langsung di back4app jaringan anda mengizinkan koneksi websocket proyek back4gram temukan di sini kode lengkap untuk sebuah proyek contoh jaringan sosial yang dibangun dengan back4app langkah 12 – memahami bagaimana back4app mengaktifkan pesan real time sekarang kita telah membangun sistem pesan yang lengkap, mari kita lihat lebih dalam bagaimana fitur back4app memungkinkan pengiriman pesan secara real time infrastruktur query langsung fitur live query back4app dibangun di atas websockets, yang menyediakan koneksi yang persisten antara klien dan server ini secara fundamental berbeda dari model permintaan/respons http tradisional api rest tradisional klien membuat permintaan → server merespons → koneksi ditutup websockets/query langsung klien membangun koneksi yang persisten → server dapat mengirim pembaruan kapan saja koneksi yang persisten inilah yang memungkinkan kemampuan real time dalam sistem pesan kami ketika pesan baru dibuat, back4app secara otomatis mengirimkan pembaruan tersebut ke semua klien yang berlangganan tanpa mereka harus melakukan polling ke server model langganan parse server model langganan di parse server berbasis kueri ini berarti anda berlangganan pada kueri tertentu (misalnya, "semua pesan dalam percakapan x") anda menerima pembaruan hanya untuk objek yang cocok dengan kueri tersebut anda dapat menerima berbagai jenis peristiwa ( buat , perbarui , hapus , dll ) pendekatan berbasis kueri ini sangat kuat karena memungkinkan langganan yang tepat dalam sistem pesan kami, kami hanya berlangganan pada pesan untuk percakapan aktif, yang jauh lebih efisien daripada berlangganan pada semua pesan pertimbangan basis data saat menggunakan live query dengan back4app, ada beberapa pertimbangan basis data yang penting pengindeksan pastikan bahwa bidang yang digunakan dalam kueri langganan diindeks untuk kinerja yang lebih baik ukuran data jaga objek tetap kecil untuk mengurangi ukuran payload dan meningkatkan kinerja skalabilitas koneksi live query menggunakan sumber daya, jadi pertimbangkan ini saat menskalakan aplikasi anda untuk kinerja optimal, pertimbangkan membuat indeks pada percakapan bidang dalam kelas pesan menggunakan pointer daripada menyematkan objek besar mengelola siklus hidup langganan untuk menghindari kebocoran memori pertimbangan keamanan saat menerapkan pesan waktu nyata, keamanan sangat penting acls dan clps gunakan daftar kontrol akses dan izin tingkat kelas untuk melindungi data anda autentikasi koneksi hanya pengguna yang terautentikasi yang boleh membuat koneksi live query validasi data validasi konten pesan di sisi server menggunakan cloud code pembatasan laju terapkan pembatasan laju untuk mencegah penyalahgunaan sebagai contoh, anda mungkin ingin menggunakan cloud code untuk memvalidasi dan membersihkan pesan sebelum disimpan // 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 "); } }); proyek back4gram temukan di sini kode lengkap untuk sebuah proyek contoh jaringan sosial yang dibangun dengan back4app langkah 13 – menguji dan mengoptimalkan sistem pesan untuk memastikan sistem pesan anda berfungsi dengan baik, anda harus mengujinya secara menyeluruh pengujian fungsionalitas dasar pengiriman pesan verifikasi bahwa pesan dapat dikirim dan diterima pembuatan percakapan uji pembuatan percakapan baru pencarian pengguna konfirmasi bahwa pengguna dapat ditemukan dan percakapan dimulai pembaruan ui periksa bahwa indikator pengetikan, daftar pesan, dan daftar percakapan diperbarui dengan benar pengujian multi pengguna untuk menguji sistem pesan dengan benar, anda perlu menguji dengan beberapa pengguna buka dua jendela atau tab browser masuk sebagai pengguna yang berbeda di masing masing mulai percakapan di antara mereka kirim pesan bolak balik uji indikator pengetikan dan pembaruan waktu nyata optimisasi kinerja untuk aplikasi yang lebih besar, pertimbangkan optimisasi berikut paginasi muat pesan dalam batch daripada semuanya sekaligus manajemen koneksi hanya buat koneksi live query untuk percakapan yang aktif kueri efisien gunakan kueri yang terarah dan sertakan hanya bidang yang diperlukan caching terapkan caching sisi klien untuk data yang sering diakses berikut adalah contoh penerapan paginasi untuk pemuatan pesan 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; } }; penanganan kesalahan dan pemulihan penanganan kesalahan yang kuat sangat penting untuk aplikasi waktu nyata kegagalan koneksi implementasikan logika penyambungan kembali untuk kegagalan websocket kegagalan pesan tangani pengiriman pesan yang gagal dan sediakan opsi percobaan ulang pemulihan status pulihkan status aplikasi setelah gangguan koneksi sebagai contoh, anda mungkin menambahkan pemantauan koneksi // 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 }); kesimpulan dalam tutorial ini, anda telah membangun sistem pesan waktu nyata yang komprehensif untuk jejaring sosial anda menggunakan back4app anda telah mengimplementasikan pesan antar pengguna membuat sistem di mana pengguna dapat menemukan dan mengirim pesan satu sama lain pembaruan waktu nyata menggunakan live query back4app untuk mengirim pesan secara instan indikator mengetik meningkatkan pengalaman pengguna dengan notifikasi mengetik waktu nyata manajemen percakapan membangun antarmuka untuk melihat dan mengelola beberapa percakapan fitur live query back4app menyediakan infrastruktur waktu nyata yang diperlukan untuk membuat ini mungkin tanpa harus mengelola server websocket yang kompleks atau masalah penskalaan dengan memanfaatkan model langganan bawaan parse server, anda dapat membuat sistem pesan yang responsif dan efisien sistem pesan yang telah anda bangun menyediakan fondasi yang solid yang dapat anda tingkatkan dengan fitur tambahan langkah selanjutnya bukti bacaan implementasikan pelacakan status bacaan pesan percakapan grup perluas sistem untuk mendukung banyak peserta berbagi media tambahkan dukungan untuk gambar, video, dan lampiran lainnya reaksi pesan izinkan pengguna untuk bereaksi terhadap pesan dengan emoji penghapusan pesan implementasikan kemampuan untuk menghapus atau mengedit pesan pencarian lanjutan tambahkan kemampuan pencarian dalam percakapan untuk kode lengkap dari aplikasi jejaring sosial back4gram, termasuk sistem pesannya, anda dapat memeriksa repositori github https //github com/templates back4app/back4gram kombinasi database, api, fungsi cloud, penyimpanan file, manajemen pengguna, dan kemampuan real time dari back4app menjadikannya pilihan yang sangat baik untuk membangun aplikasi jejaring sosial yang kaya fitur dengan menggunakan back4app, anda dapat fokus pada menciptakan pengalaman pengguna yang hebat daripada mengelola infrastruktur backend yang kompleks