Project Templates
Social Network
Cara Membangun Jaringan Sosial dengan React
121 mnt
pendahuluan dalam tutorial ini, anda akan membangun back4gram, sebuah platform jejaring sosial yang lengkap dan mirip dengan instagram back4gram memungkinkan pengguna untuk membuat akun, membagikan pos dengan gambar, berinteraksi melalui suka dan komentar, mencari konten, dan berkomunikasi melalui pesan waktu nyata proyek ini menunjukkan cara menggabungkan kemampuan frontend react yang kuat dengan layanan backend back4app yang tangguh untuk membuat aplikasi sosial modern yang kaya fitur react adalah pilihan yang sempurna untuk frontend jejaring sosial karena arsitektur berbasis komponen, yang memungkinkan elemen ui yang dapat digunakan kembali dan rendering yang efisien sementara itu, back4app menyediakan backend parse server yang dikelola yang menangani otentikasi pengguna, penyimpanan data, unggahan file, dan fitur waktu nyata tanpa memerlukan anda untuk membangun infrastruktur server yang kompleks dari awal dengan menyelesaikan tutorial ini, anda akan membangun jejaring sosial yang lengkap dengan autentikasi pengguna (daftar, masuk, reset kata sandi) manajemen profil pembuatan pos dengan unggahan gambar interaksi sosial (suka, komentar) pesan waktu nyata dengan indikator pengetikan fungsi pencarian konten pengaturan dan preferensi pengguna sepanjang jalan, anda akan mendapatkan keterampilan berharga dalam pengembangan react dengan hooks dan konteks pengembangan ui dengan chakra ui integrasi parse server melalui back4app manajemen data waktu nyata dengan livequery alur autentikasi pengguna penanganan unggahan file implementasi desain responsif apakah anda ingin meluncurkan platform sosial anda sendiri atau hanya ingin memahami bagaimana jaringan sosial modern dibangun, tutorial ini akan memberikan anda pengetahuan dan pengalaman praktis untuk mencapai tujuan anda di mana saja anda dapat mengakses kode lengkap di github prasyarat untuk menyelesaikan tutorial ini, anda akan membutuhkan akun back4app daftar untuk akun gratis di back4app com https //www back4app com/ anda akan menggunakan ini untuk membuat dan mengelola layanan backend anda node js dan npm terinstal di mesin lokal anda instal node js (versi 14 x atau lebih baru) dan npm dari nodejs org https //nodejs org/ verifikasi instalasi anda dengan menjalankan node v dan npm v di terminal anda pemahaman dasar tentang react keterampilan dengan komponen react, hooks, dan jsx jika anda perlu menyegarkan pengetahuan tentang react, periksa dokumentasi resmi react https //reactjs org/docs/getting started html editor kode editor kode modern seperti visual studio code, sublime text, atau atom git (opsional) untuk pengendalian versi dan mengikuti repositori sumber daya tambahan dokumentasi back4app https //www back4app com/docs/get started/welcome panduan javascript parse https //docs parseplatform org/js/guide/ dokumentasi chakra ui https //chakra ui com/docs/getting started dokumentasi react router https //reactrouter com/en/main langkah 1 — menyiapkan backend back4app dalam langkah ini, anda akan membuat proyek back4app baru dan mengonfigurasi skema basis data yang diperlukan untuk aplikasi jejaring sosial anda back4app menyediakan parse server yang dikelola yang akan menangani otentikasi pengguna, penyimpanan data, dan fitur waktu nyata membuat proyek back4app baru masuk ke akun back4app anda dan navigasikan ke dasbor klik tombol "buat aplikasi baru" masukkan "back4gram" sebagai nama aplikasi anda, pilih wilayah server terdekat, dan klik "buat" setelah aplikasi anda dibuat, anda akan diarahkan ke dasbor aplikasi memahami skema basis data sebelum membuat kelas di basis data anda, mari kita pahami model data yang diperlukan untuk jejaring sosial kita berdasarkan kebutuhan aplikasi kita, kita akan memerlukan kelas kelas berikut pengguna (sudah ada secara default di parse) kelas ini menangani otentikasi pengguna dan informasi profil kami akan memperluasnya dengan bidang tambahan seperti bio dan avatar pos menyimpan kiriman pengguna termasuk konten teks dan gambar bidang konten (string), penulis (pointer ke pengguna), gambar (file), suka (nomor), komentar (array), dibuatpada (tanggal) komentar menyimpan komentar pada pos bidang konten (string), penulis (pointer ke pengguna), pos (pointer ke pos), dibuatpada (tanggal) percakapan mewakili percakapan obrolan antara pengguna bidang peserta (array pointers ke pengguna), pesanterakhir (string), diperbaruipada (tanggal) pesan pesan individu dalam sebuah percakapan bidang teks (string), pengirim (pointer ke pengguna), percakapan (pointer ke percakapan), dibuatpada (tanggal) status pengetikan (untuk indikator pengetikan waktu nyata) melacak ketika pengguna mengetik dalam sebuah percakapan bidang pengguna (penunjuk ke pengguna), percakapan (penunjuk ke percakapan), sedang mengetik (boolean) membuat kelas database sekarang, mari kita buat kelas kelas ini di database back4app anda navigasikan ke bagian "database" di dasbor back4app anda memperluas kelas pengguna klik pada kelas "user" yang sudah ada tambahkan kolom berikut bio (tipe string) avatar (tipe berkas) pengikut (tipe angka, default 0) berikut (tipe angka, default 0) membuat kelas post klik "buat kelas" masukkan "post" sebagai nama kelas dan pilih "buat kelas kosong" tambahkan kolom berikut konten (tipe string) penulis (tipe pointer ke user) gambar (tipe file) suka (tipe angka, default 0) komentar (tipe array) dibuatpada (tipe tanggal, ditambahkan secara otomatis) membuat kelas komentar klik "buat kelas" masukkan "komentar" sebagai nama kelas dan pilih "buat kelas kosong" tambahkan kolom berikut konten (tipe string) penulis (tipe pointer ke user) pos (tipe penunjuk ke pos) dibuatpada (tipe tanggal, ditambahkan secara otomatis) membuat kelas percakapan klik "buat kelas" masukkan "percakapan" sebagai nama kelas dan pilih "buat kelas kosong" tambahkan kolom berikut peserta (tipe array) pesanterakhir (tipe string) diperbaruipada (tipe tanggal, ditambahkan secara otomatis) membuat kelas pesan klik "buat kelas" masukkan "pesan" sebagai nama kelas dan pilih "buat kelas kosong" tambahkan kolom berikut teks (tipe string) pengirim (tipe pointer ke user) percakapan (tipe penunjuk ke percakapan) dibuatpada (tipe tanggal, ditambahkan secara otomatis) membuat kelas typingstatus klik "buat kelas" masukkan "typingstatus" sebagai nama kelas dan pilih "buat kelas kosong" tambahkan kolom berikut pengguna (tipe pointer ke pengguna) percakapan (tipe penunjuk ke percakapan) sedangmengetik (tipe boolean) mengatur izin kelas (opsional) untuk memastikan keamanan data, kita perlu mengonfigurasi daftar kontrol akses (acl) yang sesuai untuk setiap kelas navigasikan ke bagian "keamanan & kunci" di dasbor back4app anda di bawah "keamanan tingkat kelas", konfigurasikan izin berikut kelas pengguna akses baca publik diaktifkan (agar pengguna dapat melihat profil pengguna lain) akses tulis publik dinonaktifkan (pengguna hanya dapat memodifikasi profil mereka sendiri) kelas pos akses baca publik diaktifkan (semua orang dapat melihat pos) akses tulis publik diaktifkan (pengguna yang terautentikasi dapat membuat pos) tambahkan clp untuk pembaruan/penghapusan agar hanya terbatas pada penulis kelas komentar akses baca publik diaktifkan (semua orang dapat melihat komentar) akses tulis publik diaktifkan (pengguna yang terautentikasi dapat membuat komentar) tambahkan clp untuk pembaruan/penghapusan agar hanya terbatas pada penulis kelas percakapan akses baca publik dinonaktifkan (percakapan bersifat pribadi) akses tulis publik diaktifkan (pengguna yang terautentikasi dapat membuat percakapan) tambahkan clp untuk membatasi akses baca/tulis kepada peserta percakapan kelas pesan akses baca publik dinonaktifkan (pesan bersifat pribadi) akses tulis publik diaktifkan (pengguna yang terautentikasi dapat mengirim pesan) tambahkan clp untuk membatasi akses baca/tulis kepada peserta percakapan kelas typingstatus akses baca publik dinonaktifkan (status pengetikan bersifat pribadi) akses tulis publik diaktifkan (pengguna yang terautentikasi dapat memperbarui status pengetikan) tambahkan clp untuk membatasi akses baca/tulis kepada peserta percakapan mengatur livequery untuk fitur waktu nyata untuk mengaktifkan fitur waktu nyata seperti pesan dan indikator pengetikan, kita perlu mengonfigurasi livequery navigasikan ke bagian "pengaturan server" di dasbor back4app anda di bawah "parse server", temukan bagian "livequery" dan aktifkan tambahkan kelas berikut untuk dipantau oleh livequery pesan statuspengetikan posting (untuk pembaruan waktu nyata pada suka dan komentar) simpan perubahan anda mendapatkan kunci aplikasi anda anda akan memerlukan kunci aplikasi back4app anda untuk menghubungkan frontend react anda ke backend navigasikan ke bagian "pengaturan aplikasi" > "keamanan & kunci" catat kunci berikut id aplikasi kunci javascript url server url server livequery (konfigurasi subdomain, untuk fitur real time) anda akan menggunakan kunci ini dalam aplikasi react anda untuk menginisialisasi parse langkah 2 — membuat proyek frontend react dalam langkah ini, anda akan menyiapkan proyek react baru dan mengonfigurasinya agar bekerja dengan backend back4app anda anda akan menginstal ketergantungan yang diperlukan, membuat struktur proyek, dan menghubungkan ke server parse anda menyiapkan proyek react baru mari kita mulai dengan membuat aplikasi react baru menggunakan create react app, yang menyediakan pengaturan build modern tanpa konfigurasi buka terminal anda dan navigasikan ke direktori tempat anda ingin membuat proyek anda jalankan perintah berikut untuk membuat aplikasi react baru npx create react app back4gram setelah proyek dibuat, navigasikan ke direktori proyek cd back4gram mulai server pengembangan untuk memastikan semuanya berfungsi npm start ini akan membuka aplikasi react baru anda di browser anda di http //localhost 3000 http //localhost 3000 menginstal ketergantungan yang diperlukan sekarang, mari kita instal paket yang kita perlukan untuk aplikasi jejaring sosial kita hentikan server pengembangan (tekan ctrl+c di terminal anda) instal sdk parse untuk menghubungkan ke back4app npm install parse instal react router untuk navigasi npm install react router dom instal chakra ui untuk komponen antarmuka pengguna kita npm install @chakra ui/react @emotion/react @emotion/styled framer motion instal utilitas ui tambahan dan pustaka ikon npm install react icons penjelasan struktur proyek mari kita atur proyek kita dengan struktur yang jelas buat direktori berikut di dalam src folder mkdir p src/components/ui src/pages src/contexts src/utils berikut adalah fungsi dari setiap direktori komponen komponen ui yang dapat digunakan kembali ui komponen ui dasar seperti tombol, formulir, modal folder komponen lain untuk fitur tertentu (misalnya, pos, komentar) halaman komponen halaman penuh yang sesuai dengan rute konteks penyedia konteks react untuk manajemen status utilitas fungsi utilitas dan pembantu membuat variabel lingkungan untuk menyimpan kredensial back4app anda dengan aman, buat sebuah env file di root proyek anda buat file baru bernama env local di root proyek touch env local buka file tersebut dan tambahkan kredensial back4app anda react app parse app id=your application id react app parse js key=your javascript key react app parse server url=https //parseapi back4app com react app parse live query url=wss\ //your app id back4app io ganti nilai placeholder dengan kredensial back4app anda yang sebenarnya dari langkah 1 pastikan untuk menambahkan env local ke dalam gitignore file anda untuk mencegah komit informasi sensitif mengonfigurasi parse sdk dengan kredensial back4app sekarang, mari kita atur parse sdk untuk terhubung ke backend back4app anda buat file baru src/utils/parseconfig js // src/utils/parseconfig js import parse from 'parse/dist/parse min js'; // inisialisasi parse parse initialize( process env react app parse app id, process env react app parse js key ); parse serverurl = process env react app parse server url; // inisialisasi live queries if (process env react app parse live query url) { parse livequeryserverurl = process env react app parse live query url; } export default parse; perbarui src/index js file anda untuk mengimpor konfigurasi parse import react from 'react'; import reactdom from 'react dom/client'; import ' /index css'; import app from ' /app'; import reportwebvitals from ' /reportwebvitals'; import ' /utils/parseconfig'; // impor konfigurasi parse const root = reactdom createroot(document getelementbyid('root')); root render( \<react strictmode> \<app /> \</react strictmode> ); reportwebvitals(); mengatur komponen aplikasi dengan routing mari kita perbarui komponen aplikasi utama untuk menyertakan routing dan penyedia chakra ui perbarui src/app js import react from 'react'; import { browserrouter as router, routes, route } from 'react router dom'; import { chakraprovider, extendtheme } from '@chakra ui/react'; // impor halaman (kita akan membuat ini selanjutnya) import landingpage from ' /pages/landingpage'; import loginpage from ' /pages/loginpage'; import signuppage from ' /pages/signuppage'; import resetpasswordpage from ' /pages/resetpasswordpage'; import feedpage from ' /pages/feedpage'; import profilepage from ' /pages/profilepage'; import postdetailspage from ' /pages/postdetailspage'; import messagespage from ' /pages/messagespage'; import searchpage from ' /pages/searchpage'; import settingspage from ' /pages/settingspage'; // buat tema kustom const theme = extendtheme({ config { initialcolormode 'dark', usesystemcolormode false, }, colors { brand { 50 '#e5f4ff', 100 '#b8dcff', 200 '#8ac5ff', 300 '#5cadff', 400 '#2e96ff', 500 '#147dff', 600 '#0061cc', 700 '#004799', 800 '#002d66', 900 '#001433', }, }, }); function app() { return ( \<chakraprovider theme={theme}> \<router> \<routes> \<route path="/" element={\<landingpage />} /> \<route path="/login" element={\<loginpage />} /> \<route path="/signup" element={\<signuppage />} /> \<route path="/reset password" element={\<resetpasswordpage />} /> \<route path="/feed" element={\<feedpage />} /> \<route path="/profile" element={\<profilepage />} /> \<route path="/post/\ id" element={\<postdetailspage />} /> \<route path="/messages" element={\<messagespage />} /> \<route path="/search" element={\<searchpage />} /> \<route path="/settings" element={\<settingspage />} /> \</routes> \</router> \</chakraprovider> ); } export default app; membuat komponen rute terlindungi untuk mengamankan rute yang memerlukan otentikasi, mari kita buat komponen protectedroute pertama, buat authcontext untuk mengelola status otentikasi pengguna // src/contexts/authcontext js import react, { createcontext, usestate, usecontext, useeffect } from 'react'; import parse from 'parse/dist/parse min js'; const authcontext = createcontext(); export function useauth() { return usecontext(authcontext); } export function authprovider({ children }) { const \[currentuser, setcurrentuser] = usestate(null); const \[isloading, setisloading] = usestate(true); useeffect(() => { // check if user is already logged in const checkuser = async () => { try { const user = await parse user current(); setcurrentuser(user); } catch (error) { console error('error checking current user ', error); } finally { setisloading(false); } }; checkuser(); }, \[]); // login function const login = async (username, password) => { try { const user = await parse user login(username, password); setcurrentuser(user); return user; } catch (error) { throw error; } }; // signup function const signup = async (username, email, password) => { try { const user = new parse user(); user set('username', username); user set('email', email); user set('password', password); const result = await user signup(); setcurrentuser(result); return result; } catch (error) { throw error; } }; // logout function const logout = async () => { try { await parse user logout(); setcurrentuser(null); } catch (error) { throw error; } }; // reset password function const resetpassword = async (email) => { try { await parse user requestpasswordreset(email); } catch (error) { throw error; } }; const value = { currentuser, isloading, login, signup, logout, resetpassword, }; return \<authcontext provider value={value}>{children}\</authcontext provider>; } sekarang, buat komponen protectedroute // src/components/protectedroute js import react from 'react'; import { navigate } from 'react router dom'; import { useauth } from ' /contexts/authcontext'; import { flex, spinner } from '@chakra ui/react'; function protectedroute({ children }) { const { currentuser, isloading } = useauth(); if (isloading) { return ( \<flex justify="center" align="center" height="100vh"> \<spinner size="xl" /> \</flex> ); } if (!currentuser) { return \<navigate to="/login" />; } return children; } export default protectedroute; perbarui komponen aplikasi untuk menggunakan authprovider dan protectedroute // src/app js (updated) import react from 'react'; import { browserrouter as router, routes, route } from 'react router dom'; import { chakraprovider, extendtheme } from '@chakra ui/react'; import { authprovider } from ' /contexts/authcontext'; import protectedroute from ' /components/protectedroute'; // import pages import landingpage from ' /pages/landingpage'; import loginpage from ' /pages/loginpage'; import signuppage from ' /pages/signuppage'; import resetpasswordpage from ' /pages/resetpasswordpage'; import feedpage from ' /pages/feedpage'; import profilepage from ' /pages/profilepage'; import postdetailspage from ' /pages/postdetailspage'; import messagespage from ' /pages/messagespage'; import searchpage from ' /pages/searchpage'; import settingspage from ' /pages/settingspage'; // theme configuration (same as before) const theme = extendtheme({ // theme configuration }); function app() { return ( \<chakraprovider theme={theme}> \<authprovider> \<router> \<routes> \<route path="/" element={\<landingpage />} /> \<route path="/login" element={\<loginpage />} /> \<route path="/signup" element={\<signuppage />} /> \<route path="/reset password" element={\<resetpasswordpage />} /> \<route path="/feed" element={ \<protectedroute> \<feedpage /> \</protectedroute> } /> \<route path="/profile" element={ \<protectedroute> \<profilepage /> \</protectedroute> } /> \<route path="/post/\ id" element={ \<protectedroute> \<postdetailspage /> \</protectedroute> } /> \<route path="/messages" element={ \<protectedroute> \<messagespage /> \</protectedroute> } /> \<route path="/search" element={ \<protectedroute> \<searchpage /> \</protectedroute> } /> \<route path="/settings" element={ \<protectedroute> \<settingspage /> \</protectedroute> } /> \</routes> \</router> \</authprovider> \</chakraprovider> ); } export default app; membuat halaman landing dasar mari kita buat halaman landing sederhana untuk menguji pengaturan kita // src/pages/landingpage js import react from 'react'; import { box, heading, text, button, vstack, flex } from '@chakra ui/react'; import { link as routerlink } from 'react router dom'; function landingpage() { return ( \<box bg="gray 900" minh="100vh" color="white"> \<flex direction="column" align="center" justify="center" textalign="center" py={20} \> \<heading size="2xl" mb={4}> back4gram \</heading> \<text fontsize="lg" maxw="600px" mb={8}> join a vibrant community where your voice matters share stories, ideas, and moments with friends and the world \</text> \<vstack spacing={4} maxw="md" mx="auto"> \<button as={routerlink} to="/signup" colorscheme="brand" size="lg" w="full" \> create account \</button> \<button as={routerlink} to="/login" variant="outline" size="lg" w="full" \> log in \</button> \</vstack> \</flex> \</box> ); } export default landingpage; menguji pengaturan anda sekarang anda telah mengatur struktur dasar aplikasi react anda dan menghubungkannya ke back4app, mari kita uji mulai server pengembangan npm start buka browser anda dan navigasikan ke http //localhost 3000 http //localhost 3000 anda seharusnya melihat halaman landing dengan tombol untuk mendaftar atau masuk periksa konsol browser anda untuk memastikan tidak ada kesalahan terkait dengan inisialisasi parse langkah 3 — mengimplementasikan fitur autentikasi dalam langkah ini, kita akan mengimplementasikan fitur autentikasi pengguna untuk aplikasi jejaring sosial kita menggunakan parse server dari back4app kita akan memeriksa bagaimana sistem autentikasi parse bekerja dan mengimplementasikan fungsi login, pendaftaran, dan reset kata sandi memahami sistem autentikasi pengguna parse parse server dari back4app menyediakan sistem manajemen pengguna yang komprehensif melalui parse user kelas mari kita pahami bagaimana autentikasi parse bekerja dalam aplikasi kita kelas parse user kelas parse user adalah subclass khusus dari parse object yang dirancang khusus untuk manajemen pengguna dalam aplikasi back4gram kami, kami menggunakannya untuk menyimpan kredensial pengguna (nama pengguna, email, kata sandi) mengelola status otentikasi menangani token sesi secara otomatis melihat implementasi kami, kita dapat melihat bagaimana kita berinteraksi dengan kelas parse user // from signuppage js const user = new parse user(); user set('username', username); user set('email', email); user set('password', password); await user signup(); kode ini membuat objek parse user baru, mengatur bidang yang diperlukan, dan memanggil metode signup() untuk mendaftarkan pengguna di back4app alur autentikasi di parse mari kita periksa bagaimana autentikasi bekerja di aplikasi kita alur pendaftaran di signuppage js kami, kami mengumpulkan nama pengguna, email, dan kata sandi kami memvalidasi data masukan (memeriksa kolom yang kosong, format email yang valid, panjang kata sandi) kami membuat objek parse user baru dan mengatur kredensial kami memanggil signup() yang mengirimkan data ke back4app parse menghash kata sandi sebelum menyimpannya jika berhasil, pengguna secara otomatis masuk dengan token sesi alur masuk di loginpage js kami, kami mengumpulkan nama pengguna dan kata sandi kami memanggil parse user login() dengan kredensial ini parse memverifikasi kredensial terhadap data yang disimpan jika valid, parse menghasilkan token sesi token sesi secara otomatis disimpan di penyimpanan browser manajemen sesi parse secara otomatis menyertakan token sesi dalam semua permintaan api kami menggunakan parse user current() untuk mengambil pengguna yang saat ini masuk sesi bertahan di antara penyegaran halaman implementasi pendaftaran pengguna mari kita periksa komponen signuppage kita untuk memahami bagaimana pendaftaran pengguna diimplementasikan validasi formulir sebelum mengirim data ke back4app, kami memvalidasi input pengguna // from signuppage js const validateform = () => { const newerrors = {}; if (!username trim()) { newerrors username = 'username is required'; } if (!email trim()) { newerrors email = 'email is required'; } else if (!/\s+@\s+\\ \s+/ test(email)) { newerrors email = 'email is invalid'; } if (!password) { newerrors password = 'password is required'; } else if (password length < 6) { newerrors password = 'password must be at least 6 characters'; } if (password !== confirmpassword) { newerrors confirmpassword = 'passwords do not match'; } seterrors(newerrors); return object keys(newerrors) length === 0; }; validasi ini memastikan bahwa username tidak kosong email valid password terdiri dari setidaknya 6 karakter password dan konfirmasi cocok menangani kesalahan pendaftaran pengelola pendaftaran kami mencakup penanganan kesalahan untuk kesalahan spesifik parse // from signuppage js try { // create a new user const user = new parse user(); user set('username', username); user set('email', email); user set('password', password); await user signup(); toaster create({ title 'success', description 'account created successfully!', type 'success', }); navigate('/feed'); } catch (error) { toaster create({ title 'signup failed', description error message, type 'error', }); // handle specific parse errors if (error code === 202) { seterrors({ errors, username 'username already taken'}); } else if (error code === 203) { seterrors({ errors, email 'email already in use'}); } } back4app mengembalikan kode kesalahan tertentu yang dapat kita gunakan untuk memberikan umpan balik yang berguna kepada pengguna kode 202 nama pengguna sudah diambil kode 203 email sudah digunakan kode lengkap untuk pendaftaran/pendaftaran pengguna dapat ditemukan di sini mengimplementasikan login pengguna komponen loginpage kami menangani otentikasi pengguna menggunakan parse user login() form login form login mengumpulkan nama pengguna dan kata sandi // from loginpage js \<form onsubmit={handlelogin}> \<vstack spacing={4}> \<field label="username"> \<input type="text" value={username} onchange={(e) => setusername(e target value)} placeholder="your username" required /> \</field> \<field label="password" errortext={error} \> \<input type="password" value={password} onchange={(e) => setpassword(e target value)} placeholder="your password" required /> \</field> \<link as={routerlink} to="/reset password" alignself="flex end" fontsize="sm"> forgot password? \</link> \<button colorscheme="blue" width="full" type="submit" loading={isloading} \> log in \</button> \</vstack> \</form> verifikasi sesi seperti yang ditunjukkan sebelumnya, kami memeriksa sesi yang ada saat halaman login dimuat // from loginpage js useeffect(() => { const checkcurrentuser = async () => { try { const user = await parse user current(); if (user) { setcurrentuser(user); navigate('/feed'); } } catch (error) { console error('error checking current user ', error); } }; checkcurrentuser(); }, \[navigate]); ini adalah fitur kunci dari parse ia secara otomatis mengelola token sesi di penyimpanan browser, memungkinkan kami untuk dengan mudah memeriksa apakah pengguna sudah masuk mengimplementasikan reset kata sandi back4app menyediakan alur reset kata sandi bawaan dalam aplikasi kami, kami menghubungkan ke halaman reset kata sandi dari form login // from loginpage js \<link as={routerlink} to="/reset password" alignself="flex end" fontsize="sm"> forgot password? \</link> proses reset kata sandi di back4app bekerja sebagai berikut pengguna meminta reset kata sandi dengan email mereka parse mengirimkan tautan reset khusus ke email pengguna pengguna mengklik tautan dan mengatur kata sandi baru parse memperbarui hash kata sandi di database untuk menerapkan ini dalam aplikasi kami, kami akan menggunakan // example password reset implementation try { await parse user requestpasswordreset(email); // show success message } catch (error) { // handle error } mengamankan rute untuk pengguna yang terautentikasi untuk melindungi rute tertentu dalam aplikasi kami, kami menggunakan komponen protectedroute yang memeriksa apakah pengguna terautentikasi // from protectedroute js function protectedroute({ children }) { const { currentuser, isloading } = useauth(); if (isloading) { return ( \<flex justify="center" align="center" height="100vh"> \<spinner size="xl" /> \</flex> ); } if (!currentuser) { return \<navigate to="/login" />; } return children; } komponen ini menggunakan authcontext kami untuk memeriksa apakah pengguna sudah masuk menampilkan pemutar loading saat memeriksa mengalihkan ke halaman login jika tidak ada pengguna yang ditemukan merender konten yang dilindungi jika pengguna terautentikasi kami menggunakan komponen ini dalam pengaturan routing kami // from app js \<route path="/feed" element={ \<protectedroute> \<feedpage /> \</protectedroute> } /> konfigurasi autentikasi back4app back4app menyediakan beberapa opsi konfigurasi untuk autentikasi di dasbor verifikasi email anda dapat mengharuskan verifikasi email sebelum pengguna dapat masuk konfigurasikan ini di "pengaturan server" > "parse server" > "autentikasi pengguna" kebijakan kata sandi tetapkan panjang minimum kata sandi dan persyaratan kompleksitas konfigurasikan ini di "pengaturan server" > "parse server" > "autentikasi pengguna" durasi sesi kontrol berapa lama sesi pengguna tetap valid konfigurasikan ini di "pengaturan server" > "parse server" > "konfigurasi sesi" template email sesuaikan email verifikasi dan reset kata sandi konfigurasikan ini di "pengaturan aplikasi" > "template email" menguji implementasi autentikasi anda untuk memastikan sistem autentikasi anda berfungsi dengan benar uji pendaftaran pengguna coba mendaftar dengan kredensial yang valid coba mendaftar dengan nama pengguna yang sudah ada (seharusnya menunjukkan kesalahan) periksa apakah pengguna muncul di dasbor back4app anda di bawah kelas " user" uji masuk pengguna coba masuk dengan kredensial yang benar (seharusnya mengarahkan ke feed) coba masuk dengan kredensial yang salah (seharusnya menunjukkan kesalahan) uji persistensi sesi masuk dan segarkan halaman (seharusnya tetap masuk) tutup dan buka kembali browser (seharusnya tetap masuk jika sesi valid) uji rute terproteksi coba mengakses /feed saat keluar (seharusnya mengarahkan ke login) coba mengakses /feed saat masuk (seharusnya menunjukkan halaman feed) kode untuk komponen login dapat ditemukan di sini langkah 4 — mengembangkan fungsionalitas feed dalam langkah ini, anda akan mengimplementasikan fitur inti jejaring sosial feed di sinilah pengguna akan membuat postingan, melihat konten dari orang lain, dan berinteraksi melalui suka dan komentar kami akan menggunakan parse server dari back4app untuk menyimpan dan mengambil postingan, menangani unggahan file untuk gambar, dan menerapkan pembaruan waktu nyata memahami struktur halaman feed halaman feed dalam aplikasi kami memiliki tiga komponen utama sebuah sidebar untuk navigasi area feed utama dengan pembuatan dan daftar pos sebuah bagian trending (di layar yang lebih besar) mari kita periksa bagaimana ini diimplementasikan dalam feedpage js // from feedpage js main structure function feedpage() { // state and hooks return ( \<flex minh="100vh" bg="gray 800" color="white"> {/ left sidebar (navigation) /} \<box w={\['0px', '200px']} bg="gray 900" p={4} display={\['none', 'block']}> {/ navigation links /} \</box> {/ main content (feed) /} \<box flex="1" p={4} overflowy="auto"> {/ post creation form /} {/ posts list /} \</box> {/ right sidebar (trending) /} \<box w={\['0px', '250px']} bg="gray 700" p={4} display={\['none', 'block']}> {/ trending content /} \</box> \</flex> ); } tata letak responsif ini beradaptasi dengan berbagai ukuran layar, menyembunyikan sidebar di perangkat seluler membuat kelas pos di back4app sebelum menerapkan frontend, mari pastikan database back4app kita sudah disiapkan dengan baik untuk pos kelas post harus memiliki bidang berikut konten (string) konten teks dari pos gambar (file) lampiran gambar opsional penulis (pointer to user) pengguna yang membuat pos suka (number) jumlah suka pada pos disukaioleh (array) array id pengguna yang menyukai pos dibuatpada (tanggal) ditambahkan secara otomatis oleh parse tetapkan izin yang sesuai untuk kelas post akses baca publik semua orang harus dapat membaca pos akses tulis publik pengguna yang terautentikasi harus dapat membuat pos izin pembaruan/penghapusan hanya penulis yang boleh memodifikasi pos mereka mengimplementasikan pembuatan pos mari kita periksa bagaimana pembuatan pos diimplementasikan dalam komponen feedpage kami // from feedpage js post creation state const \[postcontent, setpostcontent] = usestate(''); const \[postimage, setpostimage] = usestate(null); const \[imagepreview, setimagepreview] = usestate(''); const \[issubmitting, setissubmitting] = usestate(false); // image selection handler const handleimageselect = (e) => { if (e target files && e target files\[0]) { const file = e target files\[0]; setpostimage(file); // create preview url const previewurl = url createobjecturl(file); setimagepreview(previewurl); } }; // post submission handler const handlesubmitpost = async () => { if (!postcontent trim() && !postimage) { toaster create({ title 'error', description 'please add some text or an image to your post', type 'error', }); return; } setissubmitting(true); try { // create a new post object const post = parse object extend('post'); const newpost = new post(); // set post content newpost set('content', postcontent); newpost set('author', parse user current()); newpost set('likes', 0); newpost set('likedby', \[]); // if there's an image, upload it if (postimage) { const parsefile = new parse file(postimage name, postimage); await parsefile save(); newpost set('image', parsefile); } // save the post await newpost save(); // reset form setpostcontent(''); setpostimage(null); setimagepreview(''); // refresh posts fetchposts(); toaster create({ title 'success', description 'your post has been published!', type 'success', }); } catch (error) { toaster create({ title 'error', description error message, type 'error', }); } finally { setissubmitting(false); } }; poin poin penting tentang pembuatan pos penanganan file di parse parse file digunakan untuk mengunggah gambar ke penyimpanan back4app file disimpan terlebih dahulu, kemudian dilampirkan ke objek pos back4app secara otomatis menangani penyimpanan file dan menghasilkan url membuat objek parse kita memperluas kelas 'post' dengan parse object extend('post') kita membuat instance baru dengan new post() kita mengatur properti menggunakan set() metode kita menyimpan objek ke back4app dengan save() asosiasi pengguna kita mengasosiasikan pos dengan pengguna saat ini menggunakan parse user current() ini menciptakan hubungan pointer di database antarmuka formulir pembuatan pos terlihat seperti ini {/ post creation form /} \<box mb={6} bg="gray 700" p={4} borderradius="md"> \<vstack align="stretch" spacing={4}> \<textarea placeholder="what's on your mind?" value={postcontent} onchange={(e) => setpostcontent(e target value)} minh="100px" /> {imagepreview && ( \<box position="relative"> \<image src={imagepreview} maxh="200px" borderradius="md" /> \<iconbutton icon={\<closeicon />} size="sm" position="absolute" top="2" right="2" onclick={() => { setpostimage(null); setimagepreview(''); }} /> \</box> )} \<hstack> \<button lefticon={\<attachmenticon />} onclick={() => document getelementbyid('image upload') click()} \> add image \</button> \<input id="image upload" type="file" accept="image/ " onchange={handleimageselect} display="none" /> \<button colorscheme="blue" ml="auto" isloading={issubmitting} onclick={handlesubmitpost} disabled={(!postcontent trim() && !postimage) || issubmitting} \> post \</button> \</hstack> \</vstack> \</box> mengambil dan menampilkan post sekarang mari kita lihat bagaimana kita mengambil dan menampilkan pos dari back4app // from feedpage js fetching posts const \[posts, setposts] = usestate(\[]); const \[isloading, setisloading] = usestate(true); const \[page, setpage] = usestate(0); const \[hasmore, sethasmore] = usestate(true); const postsperpage = 10; const fetchposts = async (loadmore = false) => { try { const currentpage = loadmore ? page + 1 0; // create a query for the post class const post = parse object extend('post'); const query = new parse query(post); // include the author object (pointer) query include('author'); // sort by creation date, newest first query descending('createdat'); // pagination query limit(postsperpage); query skip(currentpage postsperpage); // execute the query const results = await query find(); // process the results const fetchedposts = results map(post => ({ id post id, content post get('content'), image post get('image') ? post get('image') url() null, likes post get('likes') || 0, likedby post get('likedby') || \[], createdat post get('createdat'), author { id post get('author') id, username post get('author') get('username'), avatar post get('author') get('avatar') ? post get('author') get('avatar') url() null } })); // update state if (loadmore) { setposts(prevposts => \[ prevposts, fetchedposts]); setpage(currentpage); } else { setposts(fetchedposts); setpage(0); } // check if there are more posts to load sethasmore(results length === postsperpage); } catch (error) { console error('error fetching posts ', error); toaster create({ title 'error', description 'failed to load posts please try again ', type 'error', }); } finally { setisloading(false); } }; // load posts when component mounts useeffect(() => { fetchposts(); }, \[]); poin poin kunci tentang mengambil pos kueri parse kami membuat kueri dengan new parse query(post) kami menyertakan objek terkait dengan query include('author') kami mengurutkan dengan query descending('createdat') kami melakukan paginasi dengan query limit() dan query skip() kami mengeksekusi kueri dengan query find() memproses hasil objek parse memiliki metode get() untuk mengakses properti untuk bidang file, kami menggunakan file url() untuk mendapatkan url kami mengubah objek parse menjadi objek javascript biasa untuk status react paginasi kami menerapkan fungsionalitas "muat lebih banyak" dengan pelacakan halaman kami memeriksa apakah ada pos lain yang perlu dimuat sebelum membuat permintaan tambahan postingan ditampilkan dalam daftar {/ posts list /} {isloading ? ( \<center py={10}> \<spinner size="xl" /> \</center> ) posts length > 0 ? ( \<vstack spacing={4} align="stretch"> {posts map(post => ( \<box key={post id} p={4} bg="gray 700" borderradius="md"> {/ post header with author info /} \<hstack mb={2}> \<avatar root size="sm"> \<avatar fallback name={post author username} /> \<avatar image src={post author avatar} /> \</avatar root> \<text fontweight="bold">{post author username}\</text> \<text fontsize="sm" color="gray 400">• {formatdate(post createdat)}\</text> \</hstack> {/ post content /} \<text mb={4}>{post content}\</text> {/ post image if any /} {post image && ( \<image src={post image} maxh="400px" borderradius="md" mb={4} /> )} {/ post actions /} \<hstack> \<button variant="ghost" lefticon={\<likeicon />} onclick={() => handlelikepost(post id, post likedby)} color={post likedby includes(currentuser id) ? "blue 400" "white"} \> {post likes} likes \</button> \<button variant="ghost" lefticon={\<commenticon />} as={routerlink} to={`/post/${post id}`} \> comments \</button> \</hstack> \</box> ))} {/ load more button /} {hasmore && ( \<button onclick={() => fetchposts(true)} isloading={isloadingmore}> load more \</button> )} \</vstack> ) ( \<center py={10}> \<text>no posts yet be the first to post!\</text> \</center> )} mengimplementasikan fungsionalitas suka mari kita periksa bagaimana fungsi suka diimplementasikan // from feedpage js like functionality const handlelikepost = async (postid, likedby) => { try { const currentuserid = parse user current() id; const isliked = likedby includes(currentuserid); // get the post object const post = parse object extend('post'); const query = new parse query(post); const post = await query get(postid); // update likes count and likedby array if (isliked) { // unlike remove user from likedby and decrement likes post set('likedby', likedby filter(id => id !== currentuserid)); post set('likes', (post get('likes') || 1) 1); } else { // like add user to likedby and increment likes post set('likedby', \[ likedby, currentuserid]); post set('likes', (post get('likes') || 0) + 1); } // save the updated post await post save(); // update local state setposts(prevposts => prevposts map(p => p id === postid ? { p, likes isliked ? p likes 1 p likes + 1, likedby isliked ? p likedby filter(id => id !== currentuserid) \[ p likedby, currentuserid] } p ) ); } catch (error) { console error('error liking post ', error); toaster create({ title 'error', description 'failed to like post please try again ', type 'error', }); } }; poin poin kunci tentang fungsionalitas suka pembaruan optimis kami memperbarui ui segera sebelum server mengonfirmasi perubahan ini membuat aplikasi terasa lebih responsif pembaruan objek parse kami mengambil pos tertentu dengan query get(postid) kami memodifikasi propertinya dengan post set() kami menyimpan perubahan dengan post save() melacak suka kami mempertahankan baik jumlah ( suka ) dan daftar pengguna ( likedby ) ini memungkinkan kami untuk menunjukkan jumlah yang akurat dan menentukan apakah pengguna saat ini telah menyukai sebuah pos mengimplementasikan pembaruan waktu nyata dengan livequery (opsional) untuk membuat pembaruan feed secara real time ketika pos baru dibuat, kita dapat menggunakan parse livequery // from feedpage js livequery setup const livequerysubscription = useref(null); useeffect(() => { // set up livequery for real time updates const setuplivequery = async () => { try { const post = parse object extend('post'); const query = new parse query(post); // subscribe to new posts livequerysubscription current = await query subscribe(); // when a new post is created livequerysubscription current on('create', (post) => { // only add to feed if it's not already there setposts(prevposts => { if (prevposts some(p => p id === post id)) return prevposts; const newpost = { id post id, content post get('content'), image post get('image') ? post get('image') url() null, likes post get('likes') || 0, likedby post get('likedby') || \[], createdat post get('createdat'), author { id post get('author') id, username post get('author') get('username'), avatar post get('author') get('avatar') ? post get('author') get('avatar') url() null } }; return \[newpost, prevposts]; }); }); // when a post is updated (e g , liked) livequerysubscription current on('update', (post) => { setposts(prevposts => prevposts map(p => p id === post id ? { p, content post get('content'), image post get('image') ? post get('image') url() p image, likes post get('likes') || 0, likedby post get('likedby') || \[] } p ) ); }); } catch (error) { console error('error setting up livequery ', error); } }; setuplivequery(); // clean up subscription when component unmounts return () => { if (livequerysubscription current) { livequerysubscription current unsubscribe(); } }; }, \[]); poin kunci tentang livequery pengaturan langganan kami membuat kueri dan berlangganan dengannya dengan query subscribe() ini membangun koneksi websocket ke server livequery back4app penanganan acara kami mendengarkan acara 'create' ketika pos baru dibuat kami mendengarkan acara 'update' ketika pos dimodifikasi kami memperbarui status lokal kami sesuai pembersihan kami berhenti berlangganan ketika komponen tidak lagi terpasang untuk mencegah kebocoran memori mengoptimalkan pemuatan pos dengan paginasi kami telah menerapkan paginasi dasar dengan tombol "muat lebih banyak" mari kita tingkatkan dengan pengguliran tak terbatas // from feedpage js infinite scrolling const \[isloadingmore, setisloadingmore] = usestate(false); const feedref = useref(null); // intersection observer for infinite scrolling useeffect(() => { if (!hasmore) return; const observer = new intersectionobserver( (entries) => { if (entries\[0] isintersecting && !isloading && !isloadingmore) { loadmoreposts(); } }, { threshold 0 5 } ); const loadmoretrigger = document getelementbyid('load more trigger'); if (loadmoretrigger) { observer observe(loadmoretrigger); } return () => { if (loadmoretrigger) { observer unobserve(loadmoretrigger); } }; }, \[hasmore, isloading, isloadingmore]); const loadmoreposts = async () => { if (!hasmore || isloadingmore) return; setisloadingmore(true); try { await fetchposts(true); } finally { setisloadingmore(false); } }; dan tambahkan ini di akhir daftar pos {/ infinite scroll trigger /} {hasmore && ( \<box id="load more trigger" h="20px" /> )} poin poin penting tentang scrolling tak terbatas intersection observer kami menggunakan api intersection observer untuk mendeteksi ketika pengguna menggulir ke bawah ketika elemen pemicu menjadi terlihat, kami memuat lebih banyak pos status memuat kami melacak status memuat terpisah untuk pemuatan awal dan "muat lebih banyak" ini mencegah beberapa permintaan simultan yang terjadi pertimbangan kinerja kami hanya memuat jumlah pos tetap pada satu waktu (paginasi) kami memeriksa apakah ada pos lain yang perlu dimuat sebelum membuat permintaan tambahan optimisasi kinerja back4app untuk mengoptimalkan kinerja saat bekerja dengan back4app gunakan indeks tambahkan indeks ke bidang yang sering ditanyakan di dasbor back4app anda untuk kelas post, tambahkan indeks pada 'createdat' dan 'author' kueri selektif gunakan query select() untuk hanya mengambil bidang yang anda butuhkan ini mengurangi transfer data dan meningkatkan kinerja optimasi hitung alih alih mengambil semua pos untuk menghitungnya, gunakan query count() ini lebih efisien untuk menentukan total hitungan langkah 6 — menambahkan interaksi sosial dalam langkah ini, kita akan meningkatkan jaringan sosial kita dengan menerapkan fitur interaksi sosial kunci komentar pada pos, profil pengguna, dan pengaturan pengguna kita akan fokus pada bagaimana fitur fitur ini berinteraksi dengan backend back4app dan mekanisme yang membuatnya berfungsi menerapkan komentar pada pos komentar adalah fitur interaksi sosial yang mendasar yang memerlukan pemodelan data yang tepat di back4app mari kita periksa bagaimana aplikasi kita berinteraksi dengan parse server untuk menerapkan komentar model data back4app untuk komentar di back4app, komentar diterapkan sebagai kelas terpisah dengan hubungan ke pengguna dan pos struktur kelas komentar konten (string) konten teks dari komentar penulis (pointer ke pengguna) mengarah ke pengguna yang membuat komentar pos (pointer ke pos) mengarah ke pos yang dikomentari dibuatpada (tanggal) dikelola secara otomatis oleh parse jenis hubungan pengguna → komentar satu ke banyak (satu pengguna dapat membuat banyak komentar) pos → komentar satu ke banyak (satu pos dapat memiliki banyak komentar) mengambil komentar dari back4app halaman postdetailspage kami menggunakan kueri parse untuk mengambil komentar untuk pos tertentu // from postdetailspage js comment fetching const fetchcomments = async () => { try { // create a query on the comment class const comment = parse object extend('comment'); const query = new parse query(comment); // find comments for this specific post using a pointer equality constraint query equalto('post', postobject); // include the author information query include('author'); // sort by creation date (newest first) query descending('createdat'); // execute the query const results = await query find(); // transform parse objects to plain objects for react state const commentslist = results map(comment => ({ id comment id, content comment get('content'), createdat comment get('createdat'), author { id comment get('author') id, username comment get('author') get('username'), avatar comment get('author') get('avatar') ? comment get('author') get('avatar') url() null } })); setcomments(commentslist); } catch (error) { console error('error fetching comments ', error); toaster create({ title 'error', description 'failed to load comments', type 'error', }); } }; mekanisme kunci back4app parse object extend() membuat referensi ke kelas komentar di back4app query equalto() membuat batasan untuk menemukan hanya komentar untuk pos tertentu query include() melakukan operasi seperti join untuk mengambil objek terkait dalam satu kueri query descending() mengurutkan hasil berdasarkan bidang tertentu membuat komentar di back4app ketika seorang pengguna menambahkan komentar, kami membuat objek parse baru dan membangun hubungan // from postdetailspage js adding a comment const handleaddcomment = async (e) => { e preventdefault(); if (!newcomment trim()) { return; } setiscommenting(true); try { // create a new comment object in back4app const comment = parse object extend('comment'); const comment = new comment(); // set comment data and relationships comment set('content', newcomment); comment set('author', parse user current()); // pointer to current user comment set('post', postobject); // pointer to current post // save the comment to back4app await comment save(); // clear the input setnewcomment(''); // refresh comments fetchcomments(); toaster create({ title 'success', description 'your comment has been added', type 'success', }); } catch (error) { toaster create({ title 'error', description error message, type 'error', }); } finally { setiscommenting(false); } }; mekanisme utama back4app new comment() membuat instance baru dari kelas komentar comment set() mengatur properti pada objek parse, termasuk pointer ke objek terkait comment save() mengirim objek ke back4app untuk penyimpanan parse user current() mendapatkan pengguna yang terautentikasi saat ini untuk menetapkan hubungan penulis keamanan back4app untuk komentar untuk mengamankan komentar di back4app dengan benar konfigurasi izin tingkat kelas (clp) baca publik (semua orang dapat membaca komentar) tulis pengguna terautentikasi saja (hanya pengguna yang masuk yang dapat mengomentari) perbarui/hapus hanya pembuat (hanya penulis komentar yang dapat memodifikasi atau menghapus) atur izin ini di dasbor back4app anda { "find" { " " true }, "get" { " " true }, "create" { " " true }, "update" { "requiresauthentication" true }, "delete" { "requiresauthentication" true }, "addfield" { "requiresauthentication" true } } langkah 7 membangun profil pengguna dengan back4app profil pengguna dalam aplikasi kami memanfaatkan kelas pengguna bawaan parse dengan bidang kustom mari kita periksa bagaimana profilepage js berinteraksi dengan back4app ekstensi kelas pengguna back4app kelas pengguna parse diperluas dengan bidang tambahan untuk jejaring sosial kami bidang pengguna kustom avatar (file) foto profil disimpan di penyimpanan file back4app bio (string) biografi pengguna website (string) url situs web pengguna displayname (string) nama tampilan pengguna mengambil data pengguna dan postingan halaman profil kami mengambil data pengguna dan postingan pengguna // from profilepage js profile data fetching const fetchuserdata = async () => { try { // get current user from parse session const currentuser = await parse user current(); if (!currentuser) { navigate('/login'); return; } setuser(currentuser); // create a query to find posts by this user const post = parse object extend('post'); const query = new parse query(post); query equalto('author', currentuser); query include('author'); query descending('createdat'); const results = await query find(); // transform parse objects to plain objects const postslist = results map(post => ({ id post id, content post get('content'), image post get('image') ? post get('image') url() null, likes post get('likes') || 0, createdat post get('createdat'), author { id post get('author') id, username post get('author') get('username'), avatar post get('author') get('avatar') ? post get('author') get('avatar') url() null } })); setposts(postslist); setstats(prevstats => ({ prevstats, posts postslist length })); } catch (error) { console error('error fetching user data ', error); toaster create({ title 'error', description 'failed to load profile data', type 'error', }); } finally { setisloading(false); } }; mekanisme kunci back4app parse user current() mengambil pengguna yang terautentikasi dari token sesi query equalto('author', currentuser) membuat batasan kesetaraan pointer untuk menemukan postingan oleh pengguna saat ini post get('image') url() mengakses url dari objek file parse yang disimpan di back4app mengimplementasikan pengaturan pengguna halaman pengaturan memungkinkan pengguna untuk memperbarui informasi profil mereka dan mengelola pengaturan akun mari kita periksa bagaimana ia berinteraksi dengan back4app // from settingspage js user settings implementation function settingspage() { const \[privacysettings, setprivacysettings] = usestate({ profilevisibility 'public', postprivacy 'friends' }); const \[twofactorauth, settwofactorauth] = usestate(false); const \[isopen, setisopen] = usestate(false); const cancelref = useref(); // save user settings to back4app const savesettings = async (settingstype, settingsdata) => { try { const currentuser = await parse user current(); if (!currentuser) { toaster create({ title 'error', description 'you must be logged in to save settings', type 'error', }); return; } // update the appropriate settings based on type switch (settingstype) { case 'privacy' currentuser set('privacysettings', settingsdata); break; case 'security' currentuser set('securitysettings', settingsdata); break; case 'notifications' currentuser set('notificationsettings', settingsdata); break; default break; } // save the user object await currentuser save(); toaster create({ title 'success', description 'your settings have been saved', type 'success', }); } catch (error) { toaster create({ title 'error', description error message, type 'error', }); } }; return ( \<box maxw="800px" mx="auto" p={4}> \<heading mb={6}>account settings\</heading> \<tabs root defaultvalue="profile"> \<tabs list> \<tabs trigger value="profile">profile\</tabs trigger> \<tabs trigger value="privacy">privacy\</tabs trigger> \<tabs trigger value="security">security\</tabs trigger> \<tabs trigger value="notifications">notifications\</tabs trigger> \<tabs indicator /> \</tabs list> {/ settings tabs content /} {/ /} \</tabs root> {/ account deactivation dialog /} \<dialog root open={isopen} onopenchange={setisopen}> {/ /} \</dialog root> \</box> ); } mekanisme kunci back4app parse user current() mendapatkan pengguna saat ini untuk memperbarui pengaturan mereka currentuser set() memperbarui properti pengguna dalam objek pengguna parse currentuser save() menyimpan perubahan ke back4app skema pengaturan pengguna back4app untuk menerapkan pengaturan di back4app tambahkan bidang ini ke kelas pengguna privacysettings (objek) objek json yang berisi preferensi privasi securitysettings (objek) objek json yang berisi pengaturan keamanan notificationsettings (objek) objek json yang berisi preferensi notifikasi contoh skema untuk objek objek ini // privacysettings { "profilevisibility" "publik", // atau "teman" atau "pribadi" "postprivacy" "teman", // atau "publik" atau "pribadi" "showactivity" true } // securitysettings { "twofactorauth" false, "loginalerts" true } // notificationsettings { "likes" true, "comments" true, "follows" true, "messages" true } fungsi cloud back4app untuk interaksi sosial untuk interaksi sosial yang lebih kompleks, anda dapat mengimplementasikan cloud functions di back4app misalnya, untuk melacak notifikasi komentar // example cloud function for comment notifications parse cloud aftersave("comment", async (request) => { // only run for new comments, not updates if (request original) return; const comment = request object; const post = comment get("post"); const commenter = request user; // skip if user is commenting on their own post const postquery = new parse query("post"); const fullpost = await postquery get(post id, { usemasterkey true }); const postauthor = fullpost get("author"); if (postauthor id === commenter id) return; // create a notification const notification = parse object extend("notification"); const notification = new notification(); notification set("type", "comment"); notification set("fromuser", commenter); notification set("touser", postauthor); notification set("post", post); notification set("read", false); await notification save(null, { usemasterkey true }); }); untuk mengimplementasikan ini pergi ke dasbor back4app anda navigasikan ke "cloud code" > "cloud functions" buat fungsi baru dengan kode di atas terapkan fungsi tersebut langkah 8 — membangun pesan real time dalam langkah ini, kita akan menerapkan fungsionalitas pesan real time menggunakan fitur livequery dari back4app ini akan memungkinkan pengguna untuk bertukar pesan secara instan tanpa menyegarkan halaman, menciptakan pengalaman obrolan dinamis yang mirip dengan platform pesan populer memahami livequery back4app sebelum terjun ke implementasi, mari kita pahami bagaimana livequery back4app bekerja apa itu livequery? livequery adalah fitur dari parse server yang memungkinkan klien untuk berlangganan pada kueri ketika objek yang cocok dengan kueri ini berubah, server secara otomatis mengirimkan pembaruan kepada klien yang berlangganan ini menciptakan fungsionalitas waktu nyata tanpa menerapkan penanganan websocket yang kompleks sendiri bagaimana livequery bekerja livequery membangun koneksi websocket antara klien dan server klien berlangganan pada kueri spesifik yang ingin mereka pantau ketika data yang cocok dengan kueri ini berubah, server mengirimkan peristiwa melalui websocket klien menerima peristiwa ini dan memperbarui ui sesuai dengan itu acara livequery buat dipicu ketika objek baru yang cocok dengan kueri dibuat perbarui dipicu ketika objek yang ada yang cocok dengan kueri diperbarui masuk dipicu ketika sebuah objek mulai mencocokkan kueri tinggalkan dipicu ketika sebuah objek tidak lagi cocok dengan kueri hapus dipicu ketika sebuah objek yang cocok dengan kueri dihapus mengatur livequery di back4app untuk mengaktifkan livequery untuk aplikasi anda, ikuti langkah langkah ini aktifkan subdomain back4app anda masuk ke akun back4app anda navigasi ke "pengaturan aplikasi" > "pengaturan server" temukan blok "url server dan kuery langsung" dan klik pada "pengaturan" periksa opsi "aktifkan subdomain back4app anda" subdomain ini akan berfungsi sebagai server livequery anda aktifkan livequery di halaman pengaturan yang sama, centang opsi "aktifkan query langsung" pilih kelas yang ingin anda pantau dengan livequery pesan (untuk pesan obrolan) status mengetik (untuk indikator mengetik) percakapan (untuk pembaruan percakapan) simpan perubahan anda catat url server livequery anda url server livequery anda akan dalam format wss\ //yourappname back4app io anda akan memerlukan url ini untuk menginisialisasi klien livequery di aplikasi react anda mengonfigurasi livequery di aplikasi react anda untuk menggunakan livequery di aplikasi react anda, anda perlu menginisialisasi klien livequery // from parseconfig js or app js parse initialize( process env react app parse app id, process env react app parse js key ); parse serverurl = process env react app parse server url; // initialize live queries with your subdomain parse livequeryserverurl = process env react app parse live query url; // e g , 'wss\ //yourappname back4app io' dalam env local file, pastikan untuk menyertakan react app parse live query url=wss\ //yourappname back4app io membuat model data untuk pesan sistem pesan kami memerlukan dua kelas utama di back4app kelas percakapan peserta (array) array dari pointer pengguna untuk pengguna dalam percakapan pesanterakhir (string) konten dari pesan terbaru tanggalpesanterakhir (tanggal) stempel waktu dari pesan terbaru diperbaruipada (tanggal) dikelola secara otomatis oleh parse kelas pesan percakapan (penunjuk) menunjuk ke percakapan yang menjadi milik pesan ini pengirim (penunjuk) menunjuk ke pengguna yang mengirim pesan konten (string) konten teks dari pesan baca (boolean) apakah pesan telah dibaca dibuatpada (tanggal) dikelola secara otomatis oleh parse kelas typingstatus percakapan (penunjuk) mengacu pada percakapan pengguna (penunjuk) menunjuk ke pengguna yang sedang mengetik sedangmengetik (boolean) apakah pengguna saat ini sedang mengetik mengimplementasikan antarmuka pesan mari kita periksa bagaimana messagespage kita mengimplementasikan pesan waktu nyata // from messagespage js component structure function messagespage() { const \[conversations, setconversations] = usestate(\[]); const \[selectedconversation, setselectedconversation] = usestate(null); const \[messages, setmessages] = usestate(\[]); const \[newmessage, setnewmessage] = usestate(''); const \[isloading, setisloading] = usestate(true); const \[typingusers, settypingusers] = usestate(\[]); const messagesendref = useref(null); const messagesubscription = useref(null); const typingsubscription = useref(null); const conversationsubscription = useref(null); const typingtimeoutref = useref(null); // rest of the component } komponen ini mempertahankan beberapa bagian dari status conversations daftar percakapan pengguna selectedconversation percakapan yang saat ini dipilih messages pesan dalam percakapan yang dipilih typingusers pengguna yang saat ini mengetik dalam percakapan ini juga menggunakan refs untuk menyimpan langganan livequery dan mengelola indikator mengetik berlangganan ke livequery untuk pesan kunci untuk pesan waktu nyata adalah berlangganan ke livequery untuk pesan dalam percakapan saat ini // from messagespage js livequery subscription for messages const subscribetomessages = async (conversation) => { try { // unsubscribe from previous subscription if exists if (messagesubscription current) { messagesubscription current unsubscribe(); } // create a query for messages in this conversation const message = parse object extend('message'); const query = new parse query(message); // create a pointer to the conversation const conversation = parse object extend('conversation'); const conversationpointer = new conversation(); conversationpointer id = conversation id; // find messages for this conversation query equalto('conversation', conversationpointer); // include the sender information query include('sender'); // subscribe to the query const subscription = await query subscribe(); messagesubscription current = subscription; // when a new message is created subscription on('create', (message) => { // add the new message to our state setmessages(prevmessages => { // check if message already exists in our list const exists = prevmessages some(m => m id === message id); if (exists) return prevmessages; // add the new message return \[ prevmessages, { id message id, content message get('content'), createdat message get('createdat'), sender { id message get('sender') id, username message get('sender') get('username'), avatar message get('sender') get('avatar') ? message get('sender') get('avatar') url() null }, read message get('read') }]; }); // scroll to bottom when new message arrives scrolltobottom(); // mark message as read if from other user if (message get('sender') id !== parse user current() id) { markmessageasread(message); } }); } catch (error) { console error('error subscribing to messages ', error); } }; mekanisme livequery kunci membuat kuery kami membuat kuery untuk pesan dalam percakapan saat ini berlangganan ke kuery kami memanggil query subscribe() untuk mulai mendengarkan perubahan menangani peristiwa kami menggunakan subscription on('create', callback) untuk menangani pesan baru berhenti berlangganan kami menyimpan referensi langganan dan berhenti berlangganan saat diperlukan mengimplementasikan indikator pengetikan dengan livequery indikator pengetikan adalah fitur real time lain yang diimplementasikan dengan livequery // from messagespage js livequery for typing indicators const subscribetotypingstatus = async (conversation) => { try { // unsubscribe from previous subscription if exists if (typingsubscription current) { typingsubscription current unsubscribe(); } // create a query for typing status in this conversation const typingstatus = parse object extend('typingstatus'); const query = new parse query(typingstatus); // create a pointer to the conversation const conversation = parse object extend('conversation'); const conversationpointer = new conversation(); conversationpointer id = conversation id; // find typing status for this conversation query equalto('conversation', conversationpointer); // include the user information query include('user'); // subscribe to the query const subscription = await query subscribe(); typingsubscription current = subscription; // when a typing status is updated subscription on('update', (typingstatus) => { const user = typingstatus get('user'); const istyping = typingstatus get('istyping'); // update typing users list settypingusers(prevtypingusers => { // if user is typing, add them to the list if (istyping) { // check if user is already in the list const exists = prevtypingusers some(u => u id === user id); if (exists) return prevtypingusers; // add user to typing list return \[ prevtypingusers, { id user id, username user get('username') }]; } else { // if user stopped typing, remove them from the list return prevtypingusers filter(u => u id !== user id); } }); }); // when a new typing status is created subscription on('create', (typingstatus) => { const user = typingstatus get('user'); const istyping = typingstatus get('istyping'); // only add to typing users if they are actually typing if (istyping && user id !== parse user current() id) { settypingusers(prevtypingusers => { // check if user is already in the list const exists = prevtypingusers some(u => u id === user id); if (exists) return prevtypingusers; // add user to typing list return \[ prevtypingusers, { id user id, username user get('username') }]; }); } }); } catch (error) { console error('error subscribing to typing status ', error); } }; memperbarui status mengetik ketika seorang pengguna mengetik, kami memperbarui status mengetik mereka // from messagespage js updating typing status const updatetypingstatus = async (istyping) => { if (!selectedconversation) return; try { const currentuser = await parse user current(); // create a pointer to the conversation const conversation = parse object extend('conversation'); const conversationpointer = new conversation(); conversationpointer id = selectedconversation id; // check if a typing status already exists const typingstatus = parse object extend('typingstatus'); const query = new parse query(typingstatus); query equalto('conversation', conversationpointer); query equalto('user', currentuser); let typingstatus = await query first(); if (typingstatus) { // update existing typing status typingstatus set('istyping', istyping); } else { // create new typing status typingstatus = new typingstatus(); typingstatus set('conversation', conversationpointer); typingstatus set('user', currentuser); typingstatus set('istyping', istyping); } await typingstatus save(); } catch (error) { console error('error updating typing status ', error); } }; // handle typing indicator with debounce const handletyping = () => { updatetypingstatus(true); // clear previous timeout if (typingtimeoutref current) { cleartimeout(typingtimeoutref current); } // set typing to false after 3 seconds of inactivity typingtimeoutref current = settimeout(() => { updatetypingstatus(false); }, 3000); }; mengirim pesan saat mengirim pesan, kami membuat objek pesan baru dan membiarkan livequery menangani pembaruan // from messagespage js sending messages const sendmessage = async (e) => { e preventdefault(); if (!newmessage trim() || !selectedconversation) return; try { const currentuser = await parse user current(); // create a pointer to the conversation const conversation = parse object extend('conversation'); const conversationpointer = new conversation(); conversationpointer id = selectedconversation id; // create a new message const message = parse object extend('message'); const message = new message(); message set('content', newmessage); message set('sender', currentuser); message set('conversation', conversationpointer); message set('read', false); await message save(); // update the conversation with the last message const conversation = await new parse query(conversation) get(selectedconversation id); conversation set('lastmessage', newmessage); conversation set('lastmessagedate', new date()); await conversation save(); // clear the input setnewmessage(''); // set typing status to false updatetypingstatus(false); } catch (error) { console error('error sending message ', error); toast({ title 'error', description 'failed to send message', status 'error', duration 3000, isclosable true, }); } }; membersihkan langganan livequery penting untuk membersihkan langganan livequery ketika tidak lagi dibutuhkan // from messagespage js cleanup useeffect(() => { // fetch initial conversations fetchconversations(); subscribetoconversations(); // cleanup subscriptions when component unmounts return () => { if (messagesubscription current) { messagesubscription current unsubscribe(); } if (typingsubscription current) { typingsubscription current unsubscribe(); } if (conversationsubscription current) { conversationsubscription current unsubscribe(); } if (typingtimeoutref current) { cleartimeout(typingtimeoutref current); } }; }, \[]); pertimbangan kinerja livequery back4app saat menerapkan livequery, pertimbangkan tips kinerja ini jadilah spesifik dengan pertanyaan berlangganan hanya untuk data yang anda butuhkan gunakan batasan untuk membatasi ruang lingkup langganan sebagai contoh, hanya berlangganan pada pesan dalam percakapan saat ini kelola langganan dengan hati hati berhenti berlangganan ketika data tidak lagi dibutuhkan buat langganan baru ketika konteks berubah simpan referensi langganan untuk berhenti berlangganan nanti gunakan acl untuk keamanan tetapkan acl yang tepat pada objek pesan dan percakapan pastikan pengguna hanya dapat mengakses percakapan yang mereka ikuti livequery menghormati acl, jadi pengguna yang tidak berwenang tidak akan menerima pembaruan optimalkan server livequery di dasbor back4app, konfigurasikan kelas yang memerlukan livequery jangan aktifkan livequery untuk kelas yang tidak memerlukan pembaruan waktu nyata langkah 9 — mengimplementasikan fungsionalitas pencarian dalam langkah ini, kita akan menerapkan fungsionalitas pencarian yang komprehensif untuk jejaring sosial kita pengguna akan dapat mencari pengguna lain, pos berdasarkan konten, dan tagar fitur ini akan memudahkan pengguna untuk menemukan konten dan terhubung dengan orang lain di platform memahami pencarian di back4app sebelum terjun ke implementasi, mari kita pahami bagaimana pencarian bekerja di back4app sistem kuery parse back4app menggunakan sistem kuery parse server untuk pencarian kuery dapat dilakukan di beberapa kelas anda dapat mencari dengan kecocokan tepat, mengandung, dimulai dengan, dll opsi pencarian teks dimulaidengan menemukan string yang dimulai dengan string tertentu mengandung menemukan string yang mengandung substring tertentu cocok menggunakan ekspresi reguler untuk pencocokan pola yang lebih kompleks tekspenuh (fitur enterprise) menyediakan kemampuan pencarian teks penuh yang canggih pertimbangan kinerja pencarian teks dapat memakan banyak sumber daya indeks harus dibuat untuk bidang yang sering dicari kuery harus dioptimalkan untuk membatasi jumlah hasil membangun halaman pencarian komponen searchpage kami akan menangani berbagai jenis pencarian dan menampilkan hasilnya mari kita periksa strukturnya // from searchpage js component structure function searchpage() { const \[searchquery, setsearchquery] = usestate(''); const \[searchtype, setsearchtype] = usestate('users'); // 'users', 'posts', 'hashtags' const \[searchresults, setsearchresults] = usestate(\[]); const \[isloading, setisloading] = usestate(false); const \[trendingtopics, settrendingtopics] = usestate(\[]); // rest of the component } komponen ini mempertahankan status untuk kueri pencarian yang dimasukkan oleh pengguna jenis pencarian yang dilakukan hasil pencarian status pemuatan topik yang sedang tren mengimplementasikan pencarian pengguna mari kita lihat bagaimana kita mencari pengguna di back4app // from searchpage js user search implementation const searchusers = async (query) => { setisloading(true); try { // create a query on the user class const userquery = new parse query(parse user); // search for usernames that contain the query string (case insensitive) userquery matches('username', new regexp(query, 'i')); // limit results to improve performance userquery limit(20); const users = await userquery find(); // transform parse objects to plain objects const userresults = users map(user => ({ id user id, username user get('username'), avatar user get('avatar') ? user get('avatar') url() null, bio user get('bio') || '' })); setsearchresults(userresults); } catch (error) { console error('error searching users ', error); toaster create({ title 'error', description 'failed to search users', type 'error', }); } finally { setisloading(false); } }; mekanisme kunci back4app new parse query(parse user) membuat kueri pada kelas pengguna userquery matches('username', new regexp(query, 'i')) melakukan pencocokan regex yang tidak sensitif terhadap huruf besar/kecil pada nama pengguna userquery limit(20) membatasi hasil untuk meningkatkan kinerja userquery find() menjalankan kueri dan mengembalikan pengguna yang cocok mengimplementasikan pencarian konten postingan sekarang mari kita lihat bagaimana kita mencari postingan berdasarkan konten // from searchpage js post search implementation const searchposts = async (query) => { setisloading(true); try { // create a query on the post class const post = parse object extend('post'); const postquery = new parse query(post); // search for posts with content containing the query string postquery matches('content', new regexp(query, 'i')); // include the author information postquery include('author'); // sort by creation date (newest first) postquery descending('createdat'); // limit results postquery limit(20); const posts = await postquery find(); // transform parse objects to plain objects const postresults = posts map(post => ({ id post id, content post get('content'), image post get('image') ? post get('image') url() null, likes post get('likes') || 0, createdat post get('createdat'), author { id post get('author') id, username post get('author') get('username'), avatar post get('author') get('avatar') ? post get('author') get('avatar') url() null } })); setsearchresults(postresults); } catch (error) { console error('error searching posts ', error); toaster create({ title 'error', description 'failed to search posts', type 'error', }); } finally { setisloading(false); } }; mekanisme utama back4app parse object extend('post') mengacu pada kelas post postquery matches('content', new regexp(query, 'i')) melakukan pencocokan regex yang tidak peka huruf besar/kecil pada konten pos postquery include('author') menyertakan informasi penulis dalam satu kueri postquery descending('createdat') mengurutkan hasil berdasarkan tanggal pembuatan mengimplementasikan pencarian hashtag pencarian hashtag memerlukan pendekatan yang berbeda kami akan mencari pos yang mengandung hashtag // from searchpage js hashtag search implementation const searchhashtags = async (query) => { setisloading(true); try { // remove # if present at the beginning const hashtagquery = query startswith('#') ? query substring(1) query; // create a query on the post class const post = parse object extend('post'); const postquery = new parse query(post); // search for posts with content containing the hashtag // we use word boundaries to find actual hashtags postquery matches('content', new regexp(`#${hashtagquery}\\\b`, 'i')); // include the author information postquery include('author'); // sort by creation date (newest first) postquery descending('createdat'); // limit results postquery limit(20); const posts = await postquery find(); // transform parse objects to plain objects const hashtagresults = posts map(post => ({ id post id, content post get('content'), image post get('image') ? post get('image') url() null, likes post get('likes') || 0, createdat post get('createdat'), author { id post get('author') id, username post get('author') get('username'), avatar post get('author') get('avatar') ? post get('author') get('avatar') url() null } })); setsearchresults(hashtagresults); } catch (error) { console error('error searching hashtags ', error); toaster create({ title 'error', description 'failed to search hashtags', type 'error', }); } finally { setisloading(false); } }; mekanisme kunci back4app kami menggunakan regex dengan batas kata ( \\\b ) untuk menemukan hashtag yang sebenarnya pendekatan ini menemukan pos di mana kontennya mengandung hashtag tertentu mengimplementasikan topik yang sedang tren untuk mengimplementasikan topik yang sedang tren, kami perlu menganalisis pos terbaru dan menghitung kemunculan hashtag // from searchpage js fetching trending topics const fetchtrendingtopics = async () => { try { // create a query on the post class const post = parse object extend('post'); const query = new parse query(post); // get posts from the last 7 days const oneweekago = new date(); oneweekago setdate(oneweekago getdate() 7); query greaterthan('createdat', oneweekago); // limit to a reasonable number for analysis query limit(500); const posts = await query find(); // extract hashtags from post content const hashtagcounts = {}; posts foreach(post => { const content = post get('content') || ''; // find all hashtags in the content const hashtags = content match(/#(\w+)/g) || \[]; // count occurrences of each hashtag hashtags foreach(hashtag => { const tag = hashtag tolowercase(); hashtagcounts\[tag] = (hashtagcounts\[tag] || 0) + 1; }); }); // convert to array and sort by count const trendingarray = object entries(hashtagcounts) map((\[hashtag, count]) => ({ hashtag, count })) sort((a, b) => b count a count) slice(0, 10); // get top 10 settrendingtopics(trendingarray); } catch (error) { console error('error fetching trending topics ', error); } }; mekanisme kunci back4app kami mengquery pos dari 7 hari terakhir menggunakan query greaterthan('createdat', oneweekago) kami menganalisis konten untuk mengekstrak dan menghitung hashtag kami mengurutkan berdasarkan frekuensi untuk menemukan hashtag yang paling populer menangani eksekusi pencarian sekarang mari kita lihat bagaimana kami menangani eksekusi pencarian berdasarkan jenis pencarian // from searchpage js search execution const handlesearch = (e) => { e preventdefault(); if (!searchquery trim()) return; switch (searchtype) { case 'users' searchusers(searchquery); break; case 'posts' searchposts(searchquery); break; case 'hashtags' searchhashtags(searchquery); break; default searchusers(searchquery); } }; mengoptimalkan pencarian di back4app untuk mengoptimalkan kinerja pencarian di back4app buat indeks navigasi ke dasbor back4app anda pergi ke "database browser" > pilih kelas (misalnya, user, post) klik pada tab "indeks" buat indeks untuk bidang yang sering dicari untuk kelas user buat indeks pada username untuk kelas post buat indeks pada content gunakan pembatasan query selalu gunakan limit() untuk membatasi jumlah hasil gunakan select() untuk hanya mengambil bidang yang anda butuhkan gunakan skip() untuk paginasi saat menangani set hasil yang besar pertimbangkan cloud functions untuk pencarian kompleks untuk logika pencarian yang lebih kompleks, terapkan cloud function ini memungkinkan anda untuk melakukan pemrosesan sisi server dan mengembalikan hasil yang dioptimalkan contoh fungsi cloud untuk pencarian lanjutan // example cloud function for advanced search parse cloud define("advancedsearch", async (request) => { const { query, type, limit = 20 } = request params; if (!query) { throw new error("search query is required"); } let results = \[]; switch (type) { case 'users' const userquery = new parse query(parse user); userquery matches('username', new regexp(query, 'i')); userquery limit(limit); results = await userquery find({ usemasterkey true }); break; case 'posts' const post = parse object extend('post'); const postquery = new parse query(post); postquery matches('content', new regexp(query, 'i')); postquery include('author'); postquery limit(limit); results = await postquery find({ usemasterkey true }); break; // add more search types as needed default throw new error("invalid search type"); } return results; }); langkah 10 — menguji dan menerapkan jaringan sosial anda dalam langkah terakhir ini, kita akan membahas cara menguji aplikasi anda, mempersiapkannya untuk produksi, menyebarkannya ke layanan hosting, dan memantau serta menskalakan backend back4app anda langkah langkah ini sangat penting untuk memastikan jaringan sosial anda berjalan lancar di lingkungan produksi mengujicoba aplikasi anda sebelum menyebarkan, penting untuk menguji aplikasi anda secara menyeluruh untuk menangkap bug atau masalah apa pun 1\ pengujian manual buat rencana pengujian yang mencakup semua fitur kunci dari aplikasi anda otentikasi pengguna uji pendaftaran dengan input yang valid dan tidak valid uji login dengan kredensial yang benar dan salah uji fungsi reset kata sandi uji ketahanan sesi dan keluar fungsi pos uji coba membuat pos dengan teks dan gambar uji melihat pos di umpan uji menyukai dan mengomentari pos uji menghapus pos interaksi sosial uji melihat profil pengguna uji komentar pada pos uji pesan waktu nyata fungsi pencarian uji pencarian untuk pengguna uji pencarian untuk pos uji pencarian hashtag pengujian lintas peramban uji di chrome, firefox, safari, dan edge uji di browser seluler 2\ pengujian otomatis untuk pengujian yang lebih kuat, terapkan pengujian otomatis // example jest test for the login component import react from 'react'; import { render, fireevent, waitfor } from '@testing library/react'; import loginpage from ' /src/pages/loginpage'; import parse from 'parse/dist/parse min js'; // mock parse jest mock('parse/dist/parse min js', () => ({ user { login jest fn() } })); test('login form submits with username and password', async () => { parse user login mockresolvedvalueonce({ id '123', get () => 'testuser' }); const { getbylabeltext, getbyrole } = render(\<loginpage />); // fill in the form fireevent change(getbylabeltext(/username/i), { target { value 'testuser' } }); fireevent change(getbylabeltext(/password/i), { target { value 'password123' } }); // submit the form fireevent click(getbyrole('button', { name /log in/i })); // check if parse user login was called with correct arguments await waitfor(() => { expect(parse user login) tohavebeencalledwith('testuser', 'password123'); }); }); 3\ pengujian back4app uji konfigurasi back4app anda fungsi cloud uji semua fungsi cloud dengan berbagai input keamanan verifikasi bahwa izin tingkat kelas anda berfungsi dengan benar livequery uji fungsionalitas waktu nyata dengan beberapa klien persiapan untuk produksi sebelum menerapkan, optimalkan aplikasi anda untuk produksi 1\ konfigurasi lingkungan buat file lingkungan terpisah untuk pengembangan dan produksi \# env development react app parse app id=your dev app id react app parse js key=your dev js key react app parse server url=https //parseapi back4app com react app parse live query url=wss\ //your dev app back4app io \# env production react app parse app id=your production app id react app parse js key=your production js key react app parse server url=https //parseapi back4app com react app parse live query url=wss\ //your prod app back4app io 2\ optimasi build optimalkan build react anda // in your package json "scripts" { "analyze" "source map explorer 'build/static/js/ js'", "build" "generate sourcemap=false react scripts build" } instal source map explorer untuk menganalisis ukuran bundle anda npm install save dev source map explorer 3\ optimisasi kinerja terapkan pemisahan kode untuk mengurangi waktu muat awal // in app js, use react lazy for route components import react, { suspense, lazy } from 'react'; import { browserrouter as router, routes, route } from 'react router dom'; import { chakraprovider } from '@chakra ui/react'; import loadingspinner from ' /components/loadingspinner'; // lazy load pages const landingpage = lazy(() => import(' /pages/landingpage')); const loginpage = lazy(() => import(' /pages/loginpage')); const feedpage = lazy(() => import(' /pages/feedpage')); // other pages function app() { return ( \<chakraprovider> \<router> \<suspense fallback={\<loadingspinner />}> \<routes> \<route path="/" element={\<landingpage />} /> \<route path="/login" element={\<loginpage />} /> \<route path="/feed" element={\<feedpage />} /> {/ other routes /} \</routes> \</suspense> \</router> \</chakraprovider> ); } menyebarkan ke layanan hosting ada beberapa opsi untuk menyebarkan aplikasi react anda 1\ menyebarkan ke vercel vercel adalah pilihan yang bagus untuk aplikasi react instal vercel cli npm install g vercel terapkan aplikasi anda vercel untuk penerapan produksi vercel prod 2\ menerapkan ke netlify netlify adalah pilihan yang sangat baik lainnya instal cli netlify npm install g netlify cli bangun aplikasi anda npm run build terapkan ke netlify netlify deploy untuk penerapan produksi netlify deploy prod 3\ menerapkan ke github pages untuk opsi penyebaran yang sederhana instal gh pages npm install save dev gh pages tambahkan ke package json "homepage" "https //yourusername github io/your repo name", "scripts" { "predeploy" "npm run build", "deploy" "gh pages d build" } sebarkan npm run deploy memantau dan menskalakan backend back4app anda seiring pertumbuhan jejaring sosial anda, anda perlu memantau dan menskalakan backend back4app anda 1\ memantau kinerja back4app menyediakan beberapa alat untuk memantau aplikasi anda dasbor analitik monitor permintaan api, penggunaan penyimpanan, dan operasi file log periksa log server untuk kesalahan dan masalah kinerja metrik kinerja lacak waktu respons dan identifikasi kemacetan untuk mengakses alat ini pergi ke dasbor back4app anda navigasi ke "analitik" untuk statistik penggunaan periksa "log" untuk log operasi yang lebih rinci 2\ menskalakan backend anda ketika basis pengguna anda tumbuh, anda mungkin perlu menskalakan backend back4app anda tingkatkan rencana anda pindah ke rencana tingkat lebih tinggi dengan lebih banyak sumber daya optimalkan kuery gunakan indeks dan batasi kuery untuk meningkatkan kinerja terapkan cache gunakan caching sisi klien untuk data yang sering diakses 3\ optimasi database optimalkan database anda untuk kinerja yang lebih baik buat indeks tambahkan indeks ke bidang yang sering ditanyakan // contoh membuat indeks pada bidang 'username' di kelas user const schema = new parse schema(' user'); schema addindex('username index', { username 1 }); schema update(); gunakan aggregation pipeline untuk operasi data yang kompleks // contoh menghitung pos oleh pengguna const pipeline = \[ { group { objectid '$author', count { $sum 1 } } } ]; const results = await parse cloud aggregate('post', pipeline); 4\ mengimplementasikan cdn untuk media untuk pengiriman gambar dan media yang lebih cepat konfigurasi cdn seperti cloudflare atau amazon cloudfront perbarui pengaturan penyimpanan file back4app anda untuk menggunakan cdn perbarui url file di aplikasi anda untuk menggunakan domain cdn 5\ menyiapkan peringatan pemantauan siapkan peringatan untuk diberitahu tentang masalah pergi ke dasbor back4app anda navigasi ke "pengaturan aplikasi" > "peringatan" konfigurasi peringatan untuk penggunaan api tinggi lonjakan tingkat kesalahan batas ukuran basis data waktu henti server ringkasan apa yang telah dicapai sepanjang tutorial ini, anda telah siapkan infrastruktur backend yang kuat membuat akun back4app dan mengonfigurasi aplikasi anda merancang skema basis data untuk pengguna, pos, komentar, dan pesan pengaturan keamanan yang dikonfigurasi dan izin tingkat kelas atur livequery untuk fungsionalitas waktu nyata membangun frontend react modern membuat ui responsif dengan komponen chakra ui mengimplementasikan routing sisi klien dengan react router mengembangkan komponen yang dapat digunakan kembali untuk pos, komentar, dan profil pengguna menghubungkan frontend anda ke back4app menggunakan parse javascript sdk diimplementasikan fitur inti jejaring sosial autentikasi pengguna (daftar, masuk, reset kata sandi) pembuatan pos dan interaksi (suka, komentar) profil pengguna dan pengaturan pesan instan antara pengguna fungsi pencarian untuk pengguna, pos, dan tagar dioptimalkan untuk produksi diimplementasikan optimasi kinerja seperti pemisahan kode atur konfigurasi lingkungan untuk pengembangan dan produksi belajar cara menerapkan aplikasi anda ke layanan hosting menjelajahi strategi pemantauan dan penskalaan untuk backend back4app anda anda sekarang memiliki dasar yang kuat untuk aplikasi jejaring sosial yang dapat diperluas dan disesuaikan untuk memenuhi kebutuhan spesifik anda langkah selanjutnya untuk memperluas aplikasi berikut adalah beberapa cara menarik untuk meningkatkan aplikasi jejaring sosial anda fitur media lanjutan tambahkan dukungan untuk unggahan dan pemutaran video terapkan filter gambar dan alat pengeditan buat cerita atau fitur konten sementara tambahkan dukungan untuk gif dan media kaya lainnya interaksi sosial yang ditingkatkan terapkan mesin rekomendasi untuk saran teman tambahkan fungsionalitas grup atau komunitas buat acara dengan kemampuan rsvp kembangkan sistem notifikasi untuk semua interaksi pengguna opsi monetisasi terapkan fitur keanggotaan premium tambahkan pembelian dalam aplikasi untuk barang digital buat pasar untuk transaksi antar pengguna integrasi dengan pemroses pembayaran seperti stripe pengalaman seluler ubah aplikasi anda menjadi aplikasi web progresif (pwa) kembangkan aplikasi mobile native menggunakan react native terapkan notifikasi push untuk perangkat seluler optimalkan ui untuk berbagai ukuran layar dan orientasi analitik dan wawasan integrasikan alat analitik untuk melacak keterlibatan pengguna buat dasbor untuk kinerja konten terapkan pengujian a/b untuk fitur baru kembangkan wawasan perilaku pengguna untuk meningkatkan platform moderasi konten terapkan penyaringan konten otomatis buat sistem pelaporan untuk konten yang tidak pantas kembangkan alat admin untuk moderasi konten gunakan pembelajaran mesin untuk analisis konten yang cerdas sumber tambahan untuk pembelajaran untuk terus memperluas pengetahuan dan keterampilan anda, berikut adalah beberapa sumber yang berharga dokumentasi dan tutorial back4app dokumentasi back4app https //www back4app com/docs/get started/welcome panduan javascript parse https //docs parseplatform org/js/guide/ saluran youtube back4app https //www youtube com/c/back4app react dan javascript modern dokumentasi react https //reactjs org/docs/getting started html javascript info https //javascript info/ kursus react di egghead io https //egghead io/q/react desain ui dan ux dokumentasi chakra ui https //chakra ui com/docs/getting started pola desain ui https //ui patterns com/ penelitian ux grup nielsen norman https //www nngroup com/articles/ optimisasi kinerja kinerja web dev https //web dev/performance scoring/ optimisasi kinerja react https //reactjs org/docs/optimizing performance html google pagespeed insights https //developers google com/speed/pagespeed/insights/ komunitas dan dukungan stack overflow https //stackoverflow\ com/questions/tagged/parse platform forum komunitas parse https //community parseplatform org/ komunitas pengembang react https //dev to/t/react ingatlah bahwa membangun jaringan sosial yang sukses adalah proses iteratif mulailah dengan fondasi yang solid (yang sekarang anda miliki), kumpulkan umpan balik pengguna, dan terus tingkatkan aplikasi anda berdasarkan pola penggunaan di dunia nyata kami berharap tutorial ini telah memberikan anda pengetahuan dan kepercayaan diri untuk membangun aplikasi luar biasa dengan react dan back4app selamat coding