Project Templates
Social Network
Echtzeit-Chat für Ihr soziales Netzwerk
53 min
einführung in diesem tutorial lernen sie, wie sie ein echtzeit nachrichtensystem für ihre social network anwendung mit back4app implementieren sie werden eine vollständige chat funktionalität erstellen, die es benutzern ermöglicht, nachrichten sofort zu senden und zu empfangen, schreibindikatoren zu sehen und gespräche zu verwalten wesentliche funktionen für ansprechende soziale plattformen back4app ist eine backend as a service (baas) plattform, die auf parse server basiert und leistungsstarke echtzeitfähigkeiten durch ihre live query funktion bietet mit der echtzeitinfrastruktur von back4app können sie reaktionsschnelle nachrichtensysteme erstellen, ohne komplexe websocket server oder skalierungsprobleme verwalten zu müssen am ende dieses tutorials haben sie ein voll funktionsfähiges nachrichtensystem erstellt, das dem in back4gram, einer social network anwendung, verwendeten ähnelt sie werden die erstellung von gesprächen, den echtzeit nachrichtenaustausch, schreibindikatoren und die benutzersuche implementieren, um ihren benutzern ein nahtloses kommunikationserlebnis zu bieten back4gram projekt finden hier den vollständigen code für ein beispielprojekt für ein soziales netzwerk erstellt mit back4app voraussetzungen um dieses tutorial abzuschließen, benötigen sie ein back4app konto sie können sich für ein kostenloses konto anmelden unter back4app com https //www back4app com ein back4app projekt, das mit dem parse javascript sdk eingerichtet ist node js auf ihrem lokalen rechner installiert grundkenntnisse in javascript, react js und back4app/parse server ein bereits implementiertes authentifizierungssystem wenn sie dies noch nicht eingerichtet haben, schauen sie sich unser tutorial zum authentifizierungssystem https //www back4app com/docs/react/authentication tutorial vertrautheit mit react hooks und dem lebenszyklus von komponenten schritt 1 – verständnis der echtzeitfähigkeiten von back4app bevor wir mit dem programmieren beginnen, lassen sie uns verstehen, wie back4app echtzeitfunktionen über seine live query funktion ermöglicht live query erklärt live query ist eine funktion des parse servers, die es clients ermöglicht, sich für abfragen anzumelden und updates zu erhalten, wenn objekte, die diesen abfragen entsprechen, erstellt, aktualisiert oder gelöscht werden dies ist perfekt für den aufbau von echtzeitanwendungen wie chatsystemen so funktioniert live query der client meldet sich für eine bestimmte abfrage an (z b "alle nachrichten im gespräch x") wenn ein passendes objekt auf dem server erstellt, aktualisiert oder gelöscht wird live query benachrichtigt automatisch alle angemeldeten clients die clients können dann ihre benutzeroberfläche als reaktion auf diese ereignisse aktualisieren im kontext eines nachrichtensystems bedeutet dies wenn eine neue nachricht gesendet wird, erhalten alle benutzer in diesem gespräch sie sofort wenn ein benutzer zu tippen beginnt, können andere benutzer in echtzeit einen tippindikator sehen wenn eine nachricht gelesen wird, können die lesebestätigungen für alle teilnehmer aktualisiert werden live query auf back4app einrichten um live query zu verwenden, müssen sie es in ihrem back4app dashboard aktivieren melden sie sich bei ihrem back4app dashboard an navigieren sie zu servereinstellungen > webhosting und live query aktivieren sie live query fügen sie die klassen hinzu, die sie mit live query verwenden möchten (in unserem fall "message" und "typingstatus") als nächstes müssen sie in ihrem clientseitigen code den live query client initialisieren // 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"; jetzt lassen sie uns mit dem entwurf unseres datenbankschemas für unser nachrichtensystem fortfahren back4gram projekt finden hier den vollständigen code für ein beispielprojekt für ein soziales netzwerk erstellt mit back4app schritt 2 – entwurf des datenbankschemas für unser nachrichtensystem benötigen wir mehrere parse klassen unterhaltung stellt einen chat zwischen zwei oder mehr benutzern dar nachricht stellt einzelne nachrichten innerhalb einer unterhaltung dar tippstatus verfolgt, wann benutzer in einer unterhaltung tippen lassen sie uns diese klassen in back4app erstellen unterhaltungsklasse die conversation klasse wird die folgenden felder haben teilnehmer (array von zeigern auf benutzer) die benutzer, die an der konversation beteiligt sind letztenachricht (string) der text der letzten nachricht aktualisiertam (datum) automatisch von parse aktualisiert, wenn sich der datensatz ändert nachrichtenklasse die nachrichtenklasse wird folgendes haben konversation (zeiger auf konversation) die konversation, zu der diese nachricht gehört absender (zeiger auf benutzer) der benutzer, der die nachricht gesendet hat text (string) der inhalt der nachricht erstelltam (datum) automatisch von parse erstellt, wenn die nachricht gesendet wird typingstatus klasse die typingstatus klasse wird tippindikatoren verfolgen benutzer (zeiger auf benutzer) der benutzer, der tippt gespräch (zeiger auf gespräch) das gespräch, in dem getippt wird tippt (boolean) ob der benutzer gerade tippt jetzt lassen sie uns unsere projektstruktur einrichten, um dieses messaging system zu implementieren back4gram projekt finden hier den vollständigen code für ein beispielprojekt für ein soziales netzwerk erstellt mit back4app schritt 3 – einrichtung der projektstruktur lass uns unseren code für das nachrichtensystem organisieren wir konzentrieren uns auf die wesentlichen komponenten src/ ├── components/ │ └── ui/ │ ├── toaster js │ └── avatar js ├── pages/ │ └── messagespage js ├── app js └── parseconfig js lass uns ein einfaches toaster js für benachrichtigungen erstellen // 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}`); } }; und aktualisiere unser app js um die nachrichtenroute einzufügen // 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; jetzt lass uns die hauptnachrichtenfunktionalität implementieren back4gram projekt finde hier den vollständigen code für ein beispielprojekt für ein soziales netzwerk erstellt mit back4app schritt 4 – erstellen der nachrichten seitenkomponente unsere messagespage js komponente wird das herzstück unseres nachrichtensystems sein sie wird zeige eine liste von gesprächen an erlaube benutzern, nachrichten zu sehen und zu senden zeige tippindikatoren an ermögliche die suche nach benutzern, um neue gespräche zu beginnen lass uns das schritt für schritt aufbauen // 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; lass uns jetzt jede der funktionen implementieren, die für unser messaging system benötigt werden back4gram projekt finde hier den vollständigen code für ein beispielprojekt für ein soziales netzwerk erstellt mit back4app schritt 5 – abrufen von benutzerunterhaltungen zuerst implementieren wir die fetchconversations funktion, die alle unterhaltungen für den aktuellen benutzer lädt 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); } }; diese funktion fragt die conversation klasse nach unterhaltungen, bei denen der aktuelle benutzer teilnehmer ist formatiert die ergebnisse zur anzeige in der benutzeroberfläche setzt die erste unterhaltung als aktiv, wenn verfügbar back4gram projekt finden hier den vollständigen code für ein beispielprojekt für ein soziales netzwerk erstellt mit back4app schritt 6 – nachrichten und echtzeit updates verwalten jetzt implementieren wir die funktionen zum abrufen von nachrichten und zum einrichten von echtzeit updates mit 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', }); } }; jetzt implementieren wir das live query abonnement für echtzeit nachrichtenupdates 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', }); } }; dieses live abfrage setup erstellt ein abonnement für neue nachrichten im aktuellen gespräch verarbeitet eingehende nachrichten in echtzeit aktualisiert die benutzeroberfläche mit neuen nachrichten, sobald sie eintreffen aktualisiert die gesprächsliste mit der neuesten nachricht und dem zeitstempel verwaltet doppelte nachrichten (die auftreten können, wenn sowohl gesendet als auch empfangen wird über live query) back4gram projekt finden hier den vollständigen code für ein beispielprojekt für ein soziales netzwerk erstellt mit back4app schritt 7 – implementierung von tippindikatoren um das benutzererlebnis zu verbessern, fügen wir echtzeit tippindikatoren hinzu 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); } }; diese implementierung abonniert statusaktualisierungen zum tippen von anderen benutzern im gespräch aktualisiert die benutzeroberfläche, wenn jemand anders tippt sendet statusaktualisierungen zum tippen, wenn der aktuelle benutzer tippt back4gram projekt finden hier den vollständigen code für ein beispielprojekt für ein soziales netzwerk erstellt mit back4app schritt 8 – nachrichten senden jetzt implementieren wir die funktionalität zum senden von nachrichten 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); } }; diese funktion erstellt und speichert eine neue nachricht in der back4app datenbank aktualisiert die letzte nachricht und den zeitstempel der konversation verhindert duplikate, wenn die nachricht über live query zurückkommt bietet sofortiges feedback an den absender back4gram projekt finden hier den vollständigen code für ein beispielprojekt für ein soziales netzwerk erstellt mit back4app schritt 9 – benutzersuche und start neuer konversationen lass uns die möglichkeit implementieren, nach benutzern zu suchen und neue gespräche zu beginnen 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', }); } }; dieser code bietet zwei wichtige funktionen für unser nachrichtensystem benutzersuche die searchusers funktion ermöglicht es benutzern, andere benutzer nach benutzernamen zu finden sie fragt die benutzerklasse in back4app ab, schließt den aktuellen benutzer von den ergebnissen aus und formatiert die daten zur anzeige gesprächserstellung die startconversation funktion kümmert sich sowohl um das finden bestehender gespräche als auch um die erstellung neuer sie überprüft, ob bereits ein gespräch zwischen den benutzern existiert wenn eines existiert, lädt es dieses gespräch und seine nachrichten wenn kein gespräch existiert, wird ein neues erstellt richtet live query abonnements für neue nachrichten und schreibstatus ein mit diesen implementierten funktionen können benutzer leicht andere benutzer finden und gespräche mit ihnen beginnen, was für ein messaging system in sozialen netzwerken unerlässlich ist back4gram projekt finden hier den vollständigen code für ein beispielprojekt für ein soziales netzwerk erstellt mit back4app schritt 10 – erstellung der chat benutzeroberfläche jetzt, da wir alle funktionen implementiert haben, lassen sie uns die benutzeroberfläche für unser messaging system erstellen die benutzeroberfläche wird aus folgendem bestehen eine seitenleiste, die alle gespräche auflistet eine suchoberfläche, um benutzer zu finden ein chatfenster, das nachrichten anzeigt ein nachrichtenfeld mit unterstützung für tippindikatoren hier ist das jsx für unsere messagespage komponente 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> ); lass uns die benutzeroberfläche in ihre hauptkomponenten aufteilen gespräche sidebar die linke seitenleiste zeigt eine liste aller gespräche jedes gespräch zeigt den namen des anderen benutzers, das avatar und die letzte nachricht benutzer können auf jedes gespräch klicken, um den chat anzuzeigen und fortzusetzen eine suchleiste oben ermöglicht es, andere benutzer zu finden, um neue gespräche zu beginnen nachrichtendarstellung der hauptbereich zeigt nachrichten für das aktive gespräch an nachrichten des aktuellen benutzers erscheinen rechts mit einem blauen hintergrund nachrichten von anderen benutzern erscheinen links mit einem grauen hintergrund jede nachricht zeigt den nachrichtentext und die uhrzeit, zu der sie gesendet wurde die nachrichtenliste scrollt automatisch nach unten, wenn neue nachrichten eintreffen nachrichteneingabe unten befindet sich ein eingabebereich, um nachrichten zu tippen und zu senden benutzer können die eingabetaste drücken, um nachrichten zu senden ein senden button ermöglicht ebenfalls das senden von nachrichten das tippen im eingabebereich aktiviert automatisch die tippindikatoren die eingabe ist deaktiviert, bis ein gespräch ausgewählt wird tippindikatoren wenn der andere benutzer tippt, erscheint ein "tippt gerade " indikator der indikator wird in echtzeit mit dem typingstatus live query abonnement aktualisiert diese benutzeroberfläche bietet eine saubere und intuitive schnittstelle für messaging, ähnlich dem, was benutzer von beliebten messaging anwendungen erwarten würden back4gram projekt finden hier den vollständigen code für ein beispielprojekt für ein soziales netzwerk erstellt mit back4app schritt 11 – testen von live query verbindungen um sicherzustellen, dass unsere live query verbindungen ordnungsgemäß funktionieren, fügen wir eine testfunktion hinzu, die die verbindung überprüft, wenn die komponente geladen wird // 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(); }, \[]); diese testfunktion versucht, ein abonnement für die message klasse zu erstellen richtet ereignis handler für verbindungsereignisse ein protokolliert die ergebnisse jedes schrittes meldet sich automatisch nach 10 sekunden ab durch das überwachen der konsolenprotokolle können sie überprüfen, dass die live abfrage url ist korrekt konfiguriert die verbindung kann hergestellt werden ereignisse werden ordnungsgemäß empfangen wenn sie probleme mit der live abfrageverbindung haben, überprüfen sie folgendes back4app live abfrage ist für ihre app aktiviert die live abfrage url ist in ihrer parse initialisierung korrekt eingestellt die nachrichtenklasse ist in der liste der live abfrageklassen in back4app hinzugefügt ihr netzwerk erlaubt websocket verbindungen back4gram projekt finden hier den vollständigen code für ein beispielprojekt für soziale netzwerke erstellt mit back4app schritt 12 – verständnis, wie back4app echtzeit messaging ermöglicht jetzt, da wir ein vollständiges messaging system aufgebaut haben, wollen wir genauer betrachten, wie die funktionen von back4app echtzeit messaging ermöglichen live query infrastruktur die live query funktion von back4app basiert auf websockets, die eine persistente verbindung zwischen dem client und dem server bereitstellen dies unterscheidet sich grundlegend vom traditionellen http anfrage/antwort modell traditionelle rest api client stellt eine anfrage → server antwortet → verbindung wird geschlossen websockets/live query client stellt eine persistente verbindung her → server kann jederzeit updates senden diese persistente verbindung ermöglicht die echtzeitfähigkeiten in unserem messaging system wenn eine neue nachricht erstellt wird, sendet back4app dieses update automatisch an alle abonnierten clients, ohne dass diese den server abfragen müssen abonnementmodell von parse server das abonnementmodell in parse server basiert auf abfragen das bedeutet sie abonnieren eine bestimmte abfrage (z b "alle nachrichten in konversation x") sie erhalten updates nur für objekte, die dieser abfrage entsprechen sie können verschiedene arten von ereignissen erhalten ( erstellen , aktualisieren , löschen , usw ) dieser abfragebasierte ansatz ist äußerst leistungsfähig, da er präzise abonnements ermöglicht in unserem nachrichtensystem abonnieren wir nur nachrichten für die aktive konversation, was viel effizienter ist, als alle nachrichten zu abonnieren datenbanküberlegungen bei der verwendung von live query mit back4app gibt es einige wichtige überlegungen zur datenbank indizierung stellen sie sicher, dass die in abonnementabfragen verwendeten felder indiziert sind, um die leistung zu verbessern datenmenge halten sie objekte klein, um die payload größe zu reduzieren und die leistung zu verbessern skalierung live query verbindungen nutzen ressourcen, berücksichtigen sie dies beim skalieren ihrer anwendung für optimale leistung sollten sie folgendes berücksichtigen indizes auf gespräch feldern in der nachrichtenklasse erstellen verwendung von zeigern anstelle von einbettung großer objekte verwaltung des lebenszyklus von abonnements, um speicherlecks zu vermeiden sicherheitsüberlegungen bei der implementierung von echtzeitnachrichten ist sicherheit entscheidend acls und clps verwenden sie zugriffskontrolllisten und klassenebene berechtigungen, um ihre daten zu schützen verbindungsauthentifizierung nur authentifizierte benutzer sollten in der lage sein, live query verbindungen herzustellen datenvalidierung validieren sie den nachrichteninhalt auf der serverseite mit cloud code ratenbegrenzung implementieren sie eine ratenbegrenzung, um missbrauch zu verhindern zum beispiel möchten sie möglicherweise cloud code verwenden, um nachrichten zu validieren und zu bereinigen, bevor sie gespeichert werden // 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 projekt finden hier den vollständigen code für ein beispielprojekt für ein soziales netzwerk erstellt mit back4app schritt 13 – testen und optimieren des messaging systems um sicherzustellen, dass ihr nachrichtensystem korrekt funktioniert, sollten sie es gründlich testen grundlegende funktionalitätstests nachrichtensendung überprüfen sie, ob nachrichten gesendet und empfangen werden können gesprächserstellung testen sie die erstellung neuer gespräche benutzersuche bestätigen sie, dass benutzer gefunden und gespräche gestartet werden können ui updates überprüfen sie, ob eingabeindikatoren, nachrichtenlisten und gesprächslisten korrekt aktualisiert werden multi user tests um ein nachrichtensystem ordnungsgemäß zu testen, müssen sie mit mehreren benutzern testen öffnen sie zwei browserfenster oder tabs melden sie sich in jedem als unterschiedliche benutzer an starten sie ein gespräch zwischen ihnen nachrichten hin und her senden testen sie die tippindikatoren und echtzeit updates leistungsoptimierung für größere anwendungen sollten sie diese optimierungen in betracht ziehen paginierung laden sie nachrichten in chargen anstatt alles auf einmal verbindungsmanagement stellen sie nur live query verbindungen für aktive gespräche her effiziente abfragen verwenden sie gezielte abfragen und schließen sie nur notwendige felder ein caching implementieren sie clientseitiges caching für häufig abgerufene daten hier ist ein beispiel für die implementierung der paginierung zum laden von nachrichten 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; } }; fehlerbehandlung und wiederherstellung robuste fehlerbehandlung ist entscheidend für echtzeitanwendungen verbindungsfehler implementieren sie eine wiederverbindungslogik für websocket fehler nachrichtenfehler behandeln sie fehlgeschlagene nachrichtenübertragungen und bieten sie wiederholungsoptionen an zustandswiederherstellung wiederherstellen des anwendungszustands nach verbindungsunterbrechungen zum beispiel könnten sie eine verbindungsüberwachung hinzufügen // 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 }); fazit in diesem tutorial haben sie ein umfassendes echtzeit nachrichtensystem für ihr soziales netzwerk mit back4app erstellt sie haben implementiert benutzer zu benutzer nachrichten ein system erstellt, in dem benutzer einander finden und nachrichten senden können echtzeit updates back4apps live query verwendet, um nachrichten sofort zu liefern tippindikatoren verbesserung der benutzererfahrung mit echtzeit tippbenachrichtigungen konversationsmanagement eine benutzeroberfläche zum anzeigen und verwalten mehrerer konversationen erstellt die live query funktion von back4app stellte die echtzeit infrastruktur bereit, die erforderlich war, um dies zu ermöglichen, ohne komplexe websocket server oder skalierungsprobleme verwalten zu müssen durch die nutzung des integrierten abonnementmodells von parse server konnten sie ein reaktionsschnelles und effizientes nachrichtensystem erstellen das messaging system, das sie aufgebaut haben, bietet eine solide grundlage, die sie mit zusätzlichen funktionen erweitern können nächste schritte lesebestätigungen implementieren sie die verfolgung des lesestatus von nachrichten gruppengespräche erweitern sie das system, um mehrere teilnehmer zu unterstützen medienfreigabe fügen sie unterstützung für bilder, videos und andere anhänge hinzu nachrichtenreaktionen ermöglichen sie es benutzern, auf nachrichten mit emojis zu reagieren nachrichtenlöschung implementieren sie die möglichkeit, nachrichten zu löschen oder zu bearbeiten erweiterte suche fügen sie suchfunktionen innerhalb von gesprächen hinzu für den vollständigen code der back4gram sozialnetzwerkanwendung, einschließlich ihres messaging systems, können sie das github repository https //github com/templates back4app/back4gram die kombination von datenbank, apis, cloud funktionen, dateispeicherung, benutzerverwaltung und echtzeitfähigkeiten von back4app macht es zu einer ausgezeichneten wahl für den aufbau funktionsreicher sozialer netzwerk anwendungen durch die verwendung von back4app können sie sich darauf konzentrieren, ein großartiges benutzererlebnis zu schaffen, anstatt komplexe backend infrastrukturen zu verwalten