MERN Stack: Pengertian dan Mengapa Populer di Kalangan Developer

Jika kamu sedang memulai perjalanan sebagai developer web, pasti sudah sering mendengar istilah "MERN Stack" di berbagai forum komunitas, tutorial online, atau dalam diskusi sama teman-teman di kantor. Memang bukan kebetulan kalau popularitas teknologi ini semakin meningkat dari tahun ke tahun. Ribuan developer di seluruh dunia, termasuk siswa-siswa BuildWithAngga, memilih stack ini untuk membuat aplikasi web yang powerful dan scalable. Teknologi MERN bukan hanya sekedar tren sesaat, melainkan kombinasi yang telah terbukti efektif dalam industri pengembangan aplikasi modern.

Pertanyaan yang mungkin terlintas di benakmu adalah: mengapa MERN menjadi pilihan utama? Apa yang membuat teknologi ini berbeda dengan stack lainya? Pelajar pemula sering kali merasa bingung dengan berbagai pilihan stack yang tersedia di industri, mulai dari LAMP, MEAN, hingga MERN. Namun, MERN memiliki keunggulan unik yang membuatnya semakin diminati oleh para profesional dan pemula yang ingin belajar cara yang benar.

Manfaat yang Akan Kamu Pelajari

Image by Freepik

Artikel ini dirancang untuk memberikan pemahaman komprehensif tentang MERN Stack dan alasan mengapa teknologi ini sangat populer dikalangan developer profesional maupun pemula. Kamu akan mendapatkan jawaban atas pertanyaan-pertanyaan penting seperti: apa saja keuntungan menggunakan MERN? Bagaimana alur kerja dari setiap komponen? Mengapa JavaScript menjadi bahasa yang dipilih untuk seluruh stack?

Sepanjang pembahasan di artikel ini, kamu akan memahami bagaimana MERN Stack memungkinkan developer untuk bekerja lebih produktif. Kamu juga akan melihat beberapa contoh proyek nyata yang membuktikan efektivitas stack ini. Selain itu, pemahaman mendalam tentang MERN akan membuka peluang karir yang lebih luas, karena skill ini sangat diminati di pasar kerja teknologi saat ini.

Di akhir artikel, kamu akan memiliki wawasan yang cukup untuk memutuskan apakah MERN adalah pilihan yang tepat untukmu, dan kamu juga akan tahu langkah-langkah awal untuk mulai belajar. Jadi, mari kita mulai dari sini dan jelajahi dunia MERN Stack bersama-sama.

Catatan penting: semua contoh dan rekomendasi pembelajaran yang kami berikan dalam artikel ini selaras dengan metodologi BuildWithAngga, yang telah terbukti efektif dalam melatih ribuan developer sukses di Indonesia dan sekitarnya. Kamu tidak hanya belajar teori, tetapi juga praktik yang relevan dengan industri.

Prerequisites untuk Memulai

Sebelum kamu memulai dengan MERN Stack, ada beberapa fondasi dasar yang perlu kamu miliki. Jangan khawatir jika belum menguasai semuanya sempurna. Kurikulum BuildWithAngga dirancang agar kamu bisa belajar prerequisites ini sambil mempelajari MERN Stack. Memahami fondasi ini lebih dahulu akan membuat perjalanan belajarmu jauh lebih mudah.

JavaScript Fundamental

JavaScript adalah jantung dari MERN Stack. Semua komponen—MongoDB, Express, React, dan Node.js—semuanya menggunakan JavaScript. Kamu harus memahami konsep-konsep penting ini:

  • Variable (var, let, const) dan scope yang berbeda pada setiap jenis
  • Function dan cara menggunakannya berulang kali
  • Async/Await untuk menangani operasi yang memakan waktu tanpa membuat aplikasi membeku

Bayangkan kamu memesan makanan di restoran. Kamu tidak menunggu sampai makanan selesai—kamu bersantai dan tunggu pemberitahuan. Itulah cara async/await bekerja.

HTML dan CSS Dasar

React akan menangani sebagian besar HTML dan CSS, tetapi kamu tetap perlu memahami dasar-dasarnya. HTML adalah struktur halaman, CSS adalah tampilan visualnya.

Untuk HTML yang perlu kamu tahu:

  • Tag dasar seperti div, span, button, input, form
  • Atribut seperti id, class, dan data attributes

Untuk CSS yang perlu kamu kuasai:

  • Selectors (element, class, id)
  • Properties dasar seperti color, font-size, padding, margin
  • Layout menggunakan flexbox atau grid

Di BuildWithAngga, kamu akan menggunakan Tailwind CSS yang membuat styling lebih cepat.

Konsep REST API

REST API adalah cara frontend dan backend berkomunikasi. Frontend mengirim request, backend merespons dengan data.

Pelajari HTTP methods yang paling sering digunakan:

  • GET untuk mengambil data
  • POST untuk membuat data baru
  • PUT untuk mengganti seluruh data
  • DELETE untuk menghapus data
  • PATCH untuk mengubah sebagian data

Juga pahami status codes penting:

  • 200 = OK, request berhasil
  • 201 = Created, data baru berhasil dibuat
  • 404 = Not Found, data tidak ditemukan
  • 500 = Server Error, ada masalah di server

Terminal Command Dasar

Kamu akan menghabiskan banyak waktu di terminal, jadi mulai terbiasa sekarang. Terminal hanya alat untuk berkomunikasi dengan komputer dengan cara lebih direkter.

Command dasar yang penting:

  • ls atau dir untuk melihat file dan folder
  • cd untuk berpindah direktori
  • mkdir untuk membuat folder baru
  • npm install untuk mengunduh package
  • npm start untuk menjalankan aplikasi

Catatan Penting untuk Kamu

Jika belum familiar dengan semua prerequisites di atas, tidak perlu khawatir. Banyak developer sukses belajar prerequisites sambil belajar MERN Stack. Dokumentasi resmi dari Node.js, React, Express, dan MongoDB sangat membantu dan ditulis dengan jelas. Komunitas BuildWithAngga juga aktif membantu pemula.

Strategi terbaik adalah mulai dengan apa yang kamu tahu. Ketika menemui konsep yang tidak dipahami, berhenti sejenak untuk memahaminya. Jangan terburu-buru melanjutkan tanpa benar-benar mengerti. Setiap konsep adalah building block yang akan kamu gunakan berkali-kali dalam proyek MERN Stack kamu, jadi investasi waktu di sini akan terbayar berlipat ganda.

Jika belum familiar, jangan khawatir—dokumentasi resmi sangat membantu dan mudah dipahami. Ada juga tutorial video interaktif, playground online, dan komunitas yang siap membantu. Gunakan semua resource ini sebanyak mungkin karena itu bagian normal dari proses belajar yang sehat.

Apa itu MERN Stack?

MERN Stack adalah kombinasi empat teknologi yang bekerja bersama-sama untuk membangun aplikasi web yang lengkap dari awal hingga akhir. Istilah "stack" sendiri berarti tumpukan atau kombinasi. Jadi, MERN Stack adalah tumpukan empat teknologi JavaScript yang saling melengkapi. Masing-masing komponen memiliki peran spesifik dalam ekosistem aplikasi web yang kamu bangun.

Untuk memahami MERN Stack dengan baik, kamu perlu mengenal setiap komponen secara mendalam. Bukan hanya mengetahui nama-namanya saja, tetapi benar-benar memahami fungsi dan peran masing-masing dalam aplikasi. Mari kita bahas satu per satu.

MongoDB: Database NoSQL yang Fleksibel

MongoDB: The World’s Leading Modern Database | MongoDB
MongoDB: The World’s Leading Modern Database | MongoDB

MongoDB adalah database yang menyimpan data dalam format yang mirip dengan JavaScript Object Notation, atau yang biasa disebut JSON. Berbeda dengan database tradisional yang menggunakan tabel dengan baris dan kolom, MongoDB menggunakan konsep dokumen dan koleksi. Bayangkan MongoDB seperti lemari file digital yang bisa menampung banyak dokumen dengan format yang lebih fleksibel.

Keunggulan MongoDB yang membuatnya populer dalam MERN Stack adalah fleksibilitasnya. Kamu tidak perlu mendefinisikan struktur data secara kaku dari awal seperti di database tradisional. Jika kamu ingin menambah field baru ke data yang sudah ada, kamu bisa melakukannya tanpa perlu mengubah seluruh struktur tabel. Ini membuat MongoDB sangat cocok untuk aplikasi yang masih dalam tahap pengembangan dan sering berubah struktur datanya.

Dalam aplikasi MERN Stack yang kamu bangun melalui kurikulum BuildWithAngga, MongoDB akan menyimpan semua data aplikasimu. Mulai dari data pengguna, data produk, data transaksi, atau apa pun yang diperlukan oleh aplikasi kamu. Data ini akan diakses dan dimanipulasi melalui backend yang dibangun dengan Express dan Node.js.

Fitur-fitur penting MongoDB yang perlu kamu ketahui:

  • Collections adalah wadah untuk menyimpan dokumen-dokumen yang sejenis
  • Documents adalah unit data terkecil, ditulis dalam format JSON-like
  • Queries adalah cara mengambil atau memodifikasi data dari database
  • Indexes membantu mempercepat pencarian data di database yang besar

Express: Backend Framework untuk Mengelola Server Logic

Express - Node.js web application framework
Express - Node.js web application framework

Express adalah framework yang berjalan di atas Node.js dan digunakan untuk membangun backend dari aplikasi web kamu. Jika MongoDB adalah tempat penyimpanan data, maka Express adalah "pegawai kantor" yang mengatur bagaimana data itu diakses, diproses, dan dikirim kepada frontend.

Express membuat proses pembuatan server web menjadi jauh lebih mudah. Tanpa Express, kamu harus menulis banyak kode kompleks hanya untuk membuat satu endpoint sederhana. Dengan Express, kamu bisa membuat REST API endpoint dalam beberapa baris kode saja. Express juga menyediakan fitur-fitur penting seperti middleware untuk memproses request, routing untuk mengarahkan request ke handler yang tepat, dan error handling untuk menangani kesalahan.

Dalam proyek-proyek BuildWithAngga, kamu akan menggunakan Express untuk membuat berbagai endpoint seperti:

  • GET /api/users untuk mengambil daftar pengguna dari database
  • POST /api/users untuk membuat pengguna baru
  • PUT /api/users/:id untuk mengubah data pengguna tertentu
  • DELETE /api/users/:id untuk menghapus pengguna tertentu

Express juga memungkinkan kamu untuk membuat middleware custom yang bisa melakukan validasi, authentikasi, atau proses lain sebelum request sampai ke handler yang sesungguhnya.

Konsep penting dalam Express yang perlu kamu pahami:

  • Routes adalah path yang mengarahkan request ke handler yang tepat
  • Middleware adalah fungsi yang dijalankan sebelum atau sesudah handler utama
  • Controllers adalah fungsi yang menangani logika bisnis dari aplikasi
  • Error handling adalah cara menangani kesalahan dengan graceful

React: Frontend Library untuk UI Interaktif

React
React

React adalah library JavaScript yang digunakan untuk membangun antarmuka pengguna yang interaktif dan dinamis. Jika kamu ingin membuat halaman web yang responsif terhadap interaksi pengguna tanpa perlu refresh halaman, React adalah pilihan yang tepat. React membuat proses pengembangan UI menjadi lebih terstruktur dengan konsep komponen yang reusable.

Konsep fundamental React yang perlu kamu pahami adalah thinking in components. Setiap bagian dari UI kamu adalah komponen yang bisa didefinisikan, digunakan kembali, dan dikombinasikan dengan komponen lain untuk membuat UI yang kompleks. Misalnya, sebuah tombol adalah komponen, sebuah form adalah komponen, sebuah card adalah komponen. Dengan cara berpikir ini, kamu bisa membuat UI yang scalable dan mudah dimaintain.

React juga menggunakan Virtual DOM, yang adalah representasi JavaScript dari DOM asli. Virtual DOM ini memungkinkan React untuk mendeteksi perubahan yang terjadi dan hanya mengupdate bagian DOM yang benar-benar berubah. Ini membuat aplikasi React menjadi jauh lebih cepat dan efisien dibandingkan dengan manipulasi DOM langsung.

Dalam pembelajaran di BuildWithAngga, kamu akan membuat komponen-komponen React seperti:

  • Functional Components yang lebih modern dan menggunakan Hooks
  • State Management untuk mengelola data yang berubah di dalam komponen
  • Props untuk mengirim data dari parent komponen ke child komponen
  • Hooks seperti useState, useEffect untuk menambah functionality ke komponen

React sangat populer karena kombinasi dari kekuatannya dalam membuat UI yang dinamis, ekosistem yang luas dengan banyak library tambahan, dan community yang sangat aktif.

Node.js: Runtime untuk Menjalankan JavaScript di Server

Node.js — Run JavaScript Everywhere
Node.js — Run JavaScript Everywhere

Node.js adalah runtime environment yang memungkinkan kamu menjalankan JavaScript di server, bukan hanya di browser. Sebelum Node.js ada, JavaScript hanya bisa dijalankan di browser saja. Node.js mengubah semuanya dengan membawa JavaScript ke backend, sehingga kamu bisa menggunakan satu bahasa untuk seluruh aplikasi web kamu.

Node.js dibangun di atas V8 engine, yang sama dengan engine yang digunakan Chrome untuk menjalankan JavaScript. Ini membuat Node.js sangat cepat dan efisien. Node.js juga memiliki event-driven, non-blocking I/O model yang sempurna untuk membuat aplikasi yang scalable dan responsive.

Dalam konteks MERN Stack, Node.js adalah fondasi yang menjalankan Express dan memproses semua backend logic. Tanpa Node.js, kamu tidak bisa menjalankan Express atau backend aplikasimu sama sekali. Node.js juga menyediakan akses ke file system, database connections, dan operasi-operasi sistem lain yang diperlukan backend.

Fitur penting Node.js yang sering kamu gunakan:

  • NPM sebagai package manager untuk mengelola dependencies
  • Event loop yang menangani operasi asynchronous
  • File system untuk membaca dan menulis file
  • HTTP module untuk membuat server web

Bagaimana Keempat Komponen Bekerja Bersama?

Sekarang kamu sudah mengenal keempat komponen MERN Stack secara individual. Saatnya kita lihat bagaimana mereka bekerja bersama-sama dalam sebuah aplikasi web yang utuh. Proses ini bisa divisualisasikan seperti berikut:

Alur Data dalam Aplikasi MERN:

  1. User berinteraksi dengan Frontend (React) - Semuanya dimulai ketika pengguna membuka halaman web aplikasi kamu. React merender komponen-komponen UI ke browser sehingga pengguna bisa melihat tampilan aplikasi. Ketika pengguna melakukan suatu aksi seperti mengklik tombol atau mengisi form, React menangani event tersebut dengan cepat.
  2. Frontend mengirim request ke Backend (Express & Node.js) - Setelah itu, React membuat HTTP request yang berisi data aksi pengguna. Request ini bisa berupa GET untuk mengambil data, POST untuk membuat data baru, PUT untuk mengubah data, atau DELETE untuk menghapus data. Request dikirim ke server backend yang sedang running di Node.js melalui jaringan internet.
  3. Backend memproses request dan berinteraksi dengan Database (MongoDB) - Express menerima request tersebut dan routing-nya mengarahkan request ke handler yang tepat berdasarkan path dan HTTP method yang digunakan. Handler di Express kemudian menjalankan business logic sesuai dengan kebutuhan aplikasi. Jika diperlukan, backend akan membuat query ke MongoDB untuk mengambil data yang diperlukan atau menyimpan data baru. MongoDB memproses query tersebut dan mengembalikan data yang diminta atau konfirmasi bahwa operasi berhasil dilakukan.
  4. Backend mengirim response kembali ke Frontend - Setelah mendapatkan data dari MongoDB, Express membungkus data atau hasil operasi tersebut dalam format JSON response yang siap untuk dikirim kembali ke frontend. Response ini dikirim kembali ke React beserta status code yang sesuai untuk menunjukkan apakah operasi berhasil atau terjadi kesalahan. React menerima response ini dan mengupdate state komponen dengan data baru dari server.
  5. Frontend menampilkan data baru ke user - Terakhir, React merender ulang komponen dengan data baru yang telah diterima dari backend. Pengguna akhirnya bisa melihat perubahan di layar tanpa perlu melakukan refresh halaman secara manual. Siklus ini akan berulang terus-menerus ketika pengguna melakukan aksi baru.

Untuk lebih mudah memahami, bayangkan seperti sistem pemesanan di sebuah warung kopi:

  • React (Frontend) adalah pelayan yang melayani pelanggan dan mencatat pesanan
  • Express & Node.js (Backend) adalah chef dan manager yang menerima pesanan dan mengelola operasi dapur
  • MongoDB (Database) adalah gudang yang menyimpan semua bahan dan catatan pesanan sebelumnya

Ketika pelanggan memesan kopi (user berinteraksi), pelayan mencatat pesanannya (React membuat request). Pelayan membawa pesanan ke dapur (request dikirim ke server). Chef melihat pesanan dan menyiapkan kopi, mungkin sambil mengecek gudang untuk bahan yang dibutuhkan (Express memproses dan query MongoDB). Setelah kopi siap, pelayan membawa kopi kembali ke pelanggan (server mengirim response). Pelanggan akhirnya bisa minum kopi (frontend menampilkan data).

Dalam proyek-proyek pembelajaran di BuildWithAngga, kamu akan membuat aplikasi sederhana yang mengikuti pola ini. Mulai dari aplikasi todo list, aplikasi manajemen produk, hingga aplikasi e-commerce yang lebih kompleks. Setiap proyek akan memperkuat pemahaman kamu tentang bagaimana keempat komponen MERN Stack bekerja bersama-sama dalam harmoni yang sempurna.

Keunggulan Utama MERN

Image by Freepik
Image by Freepik

MERN Stack bukan hanya sekedar kombinasi empat teknologi yang populer saja, tetapi juga memiliki keunggulan-keunggulan signifikan yang membuat banyak developer memilihnya untuk membangun aplikasi web modern. Keunggulan-keunggulan ini bukan hanya tentang teknologi itu sendiri, tetapi juga tentang ekosistem, komunitas, dan produktivitas yang bisa kamu dapatkan. Mari kita bahas satu per satu mengapa MERN Stack menjadi pilihan utama di industri.

Satu Bahasa (JavaScript) di Semua Layer

Salah satu keunggulan terbesar dari MERN Stack adalah kamu bisa menggunakan JavaScript untuk seluruh aplikasi web kamu, dari frontend hingga backend. Ini berarti kamu tidak perlu belajar banyak bahasa pemograman yang berbeda untuk membangun aplikasi web yang lengkap. Dalam stack lain seperti LAMP atau MEAN, kamu mungkin perlu menguasai beberapa bahasa seperti PHP atau bahasa lainnya. Dengan MERN, semuanya JavaScript.

Keuntungan ini memberikan beberapa benefit nyata yang kamu bisa rasakan langsung:

  • Kurva pembelajaran lebih landai - Setelah kamu menguasai JavaScript dengan baik, kamu sudah bisa mulai membangun aplikasi full-stack tanpa perlu waktu adaptasi dengan bahasa pemograman baru. Ini sangat efisien terutama untuk pemula yang baru memulai journey mereka sebagai developer.
  • Context switching yang minimal - Ketika developer bekerja dengan satu bahasa di seluruh stack, pikiran mereka tidak perlu terus-menerus beralih dari satu syntax ke syntax yang berbeda. Fokus tetap pada problem solving dan logic aplikasi, bukan pada menghafal syntax yang berbeda-beda.
  • Reusability code yang lebih tinggi - Beberapa logic atau utility function bisa digunakan di frontend maupun backend tanpa perlu ditulis ulang dengan bahasa lain. Misalnya, validasi form atau format data bisa diimplementasikan dengan code yang sama atau sangat mirip di kedua sisi.
  • Developer yang lebih versatile - Developer yang menguasai MERN Stack akan lebih mudah beradaptasi dengan berbagai project dan bisa berkontribusi di berbagai bagian aplikasi dengan lebih efektif.

Dalam pembelajaran di BuildWithAngga, kamu akan merasakan langsung manfaat ini. Semua konsep yang kamu pelajari tentang JavaScript di awal, akan terus berguna ketika kamu belajar React, Express, dan Node.js. Tidak ada yang terbuang, semuanya interconnected dan saling melengkapi.

Komunitas Besar dengan Banyak Resource

JavaScript adalah bahasa pemograman paling populer di dunia, dan MERN Stack menjadi salah satu pilihan utama dalam ekosistem JavaScript. Artinya, komunitas developer yang menggunakan MERN Stack sangatlah besar dan aktif. Komunitas yang besar ini menciptakan banyak resource berkualitas yang bisa membantu kamu belajar.

Keuntungan dari komunitas yang besar adalah:

  • Dokumentasi yang lengkap dan mudah dipahami - Setiap library dan framework dalam MERN Stack memiliki dokumentasi resmi yang sangat detail dan ditulis dengan baik. React, Express, Node.js, dan MongoDB semuanya memiliki dokumentasi yang bisa diakses gratis dan mudah diikuti.
  • Tutorial dan course yang melimpah - Ada ribuan tutorial, course, dan guide yang tersedia di berbagai platform baik gratis maupun berbayar. Dari YouTube, Udemy, hingga platform khusus seperti BuildWithAngga yang fokus pada pembelajaran praktis dengan kurikulum yang terstruktur.
  • Library dan tool ekosistem yang kaya - Karena komunitas yang besar, banyak developer yang menciptakan library atau tool tambahan yang bisa mempermudah development. Dari UI component library seperti Material-UI atau Chakra UI untuk React, hingga middleware dan plugin untuk Express.
  • Community support yang responsif - Ketika kamu menghadapi masalah atau pertanyaan, ada banyak tempat yang bisa kamu tanyakan. Stack Overflow memiliki ribuan pertanyaan dan jawaban tentang MERN Stack. Ada juga forum, Discord server, dan komunitas lokal yang siap membantu.
  • Job market yang luas - Karena banyak perusahaan yang menggunakan MERN Stack, permintaan developer MERN sangat tinggi di job market. Ini berarti skill yang kamu pelajari akan sangat valuable dan banyak peluang kerja yang menunggu.

Saat ini, komunitas BuildWithAngga juga berkontribusi aktif dalam ekosistem MERN. Kamu tidak hanya belajar dari guru, tetapi juga bisa belajar dari ribuan alumni yang sudah membangun aplikasi MERN yang nyata. Forum dan group discussion di komunitas ini menjadi tempat yang baik untuk bertanya dan berbagi pengalaman.

Scalable dan Cocok untuk Aplikasi Modern

MERN Stack dirancang dengan arsitektur yang memungkinkan aplikasi untuk scale dengan mudah seiring pertumbuhan data dan user. Ini bukan hanya sekedar teori, tetapi sudah dibuktikan oleh banyak startup dan perusahaan besar yang menggunakan teknologi ini untuk membangun aplikasi yang melayani jutaan user.

Scalability dalam MERN Stack bisa dilihat dari beberapa aspek:

  • Node.js dengan event-driven architecture - Node.js menggunakan event loop yang efisien untuk menangani banyak request secara concurrent tanpa perlu membuat thread baru untuk setiap request. Ini membuat server bisa menangani ribuan atau bahkan jutaan koneksi simultan dengan resource yang relatif kecil.
  • MongoDB yang flexible dan horizontal scalable - MongoDB bisa dengan mudah di-scale secara horizontal dengan menggunakan sharding. Ini berarti ketika data kamu terus bertambah, kamu bisa membagi data ke beberapa database instance tanpa perlu redesign aplikasi secara fundamental.
  • React yang efficient dengan Virtual DOM - React menggunakan Virtual DOM untuk meminimalkan manipulasi DOM yang expensive. Bahkan ketika ada banyak perubahan data, React hanya mengupdate bagian yang benar-benar berubah, sehingga aplikasi tetap responsif dan cepat.
  • Microservices-ready architecture - Arsitektur MERN memudahkan untuk memisah aplikasi menjadi microservices jika diperlukan di masa depan. Setiap service bisa ditulis dengan teknologi yang berbeda jika perlu, tetapi tetap bisa berkomunikasi dengan baik.

MERN Stack juga sangat cocok untuk membangun aplikasi modern dengan requirement yang dinamis. Apakah itu aplikasi real-time seperti chat application, dashboard dengan data yang constantly updated, atau aplikasi dengan kompleksitas bisnis yang tinggi, MERN Stack bisa menangani semuanya dengan baik.

Dalam pembelajaran praktis di BuildWithAngga, kamu akan membuat berbagai jenis aplikasi yang mengdemonstrasikan scalability ini. Dari aplikasi sederhana hingga aplikasi yang lebih kompleks dengan banyak fitur, semua akan diajarkan secara progresif sehingga kamu bisa memahami bagaimana design decision mempengaruhi scalability.

Development Lebih Cepat dengan Ekosistem yang Matang

MERN Stack memiliki ekosistem yang sudah matang dengan banyak tool, library, dan best practice yang sudah terbukti efektif. Ini berarti kamu tidak perlu reinvent the wheel untuk setiap masalah yang kamu hadapi. Banyak problem yang sudah dihadapi oleh developer lain sebelumnya, dan mereka sudah membuat solusi yang bisa kamu gunakan.

Beberapa benefit dari ekosistem yang matang ini adalah:

  • Package manager yang powerful - NPM atau Yarn adalah package manager untuk JavaScript yang memiliki repository terbesar di dunia dengan jutaan package yang siap pakai. Ini membuat instalasi dependency menjadi sangat mudah dan cepat.
  • Build tools yang advanced - Ada tool seperti Webpack, Vite, atau Parcel yang mengotomatisasi proses bundling, minification, dan optimization. Tool-tool ini membuat development menjadi lebih efisien dan hasil production build menjadi lebih optimal.
  • Development server dengan hot reload - Framework seperti Create React App atau Vite menyediakan development server yang bisa melakukan hot reload secara otomatis. Setiap kali kamu mengubah code, browser akan langsung me-refresh tanpa perlu di-refresh secara manual.
  • Testing framework yang sudah standard - Ada framework testing yang sudah menjadi standard di industri seperti Jest untuk JavaScript testing, React Testing Library untuk component testing, dan Supertest untuk API testing. Ini membuat quality assurance menjadi lebih mudah dan konsisten.
  • Linting dan formatting tools - Tool seperti ESLint dan Prettier membantu memastikan code kamu sesuai dengan best practice dan memiliki format yang konsisten. Ini bukan hanya tentang aesthetics, tetapi juga tentang maintainability dan mengurangi bugs.
  • DevTools yang powerful - Browser DevTools untuk React dan MongoDB Compass untuk database inspection memberikan visibility yang baik ke dalam aplikasi kamu, membuat debugging menjadi lebih mudah.

Dengan semua tool dan library yang tersedia, development cycle menjadi jauh lebih cepat. Fitur yang biasanya memakan waktu berminggu-minggu untuk diimplementasi, bisa diselesaikan dalam beberapa hari dengan MERN Stack. Ini adalah yang dimaksud dengan produktivitas yang tinggi.

Di BuildWithAngga, kamu akan belajar menggunakan tool-tool terbaik dari ekosistem MERN. Setiap project yang kamu buat akan menggunakan setup yang optimal dan best practice yang sudah terbukti di industri. Dengan cara ini, kamu tidak hanya belajar konsep, tetapi juga belajar bagaimana praktik development yang professional di dunia nyata.

Kombinasi dari satu bahasa, komunitas yang besar, scalability yang baik, dan ekosistem yang matang membuat MERN Stack menjadi pilihan yang sangat rational untuk developer yang ingin membangun aplikasi web modern yang berkualitas tinggi. Ini bukan hanya trend sesaat, tetapi merupakan arsitektur yang sudah terbukti dan akan terus relevan di masa depan.

Mengapa MERN Populer?

ReactJS Development Powering Netflix, BBC, Airbnb & More
ReactJS Development Powering Netflix, BBC, Airbnb & More

Popularitas MERN Stack terus meningkat dan sudah menjadi pilihan utama di industri pengembangan web. Menurut data 2025, demand untuk MERN developers terus berkembang karena perusahaan mengadopsi teknologi ini untuk fleksibilitas dan skalabilitas. Ada empat alasan utama mengapa MERN Stack mendapat perhatian besar dari industri.

Permintaan di Job Market Sangat Tinggi

MERN Stack Developer Salary Trends 2025 – Earnings & Career Growth
MERN Stack Developer Salary Trends 2025 – Earnings & Career Growth

Job market untuk MERN Stack developer sangat panas di tahun 2025. Ketika membuka job portal dan mencari "MERN" atau "JavaScript full-stack", kamu akan menemukan ribuan lowongan kerja dari startup hingga perusahaan besar. Data terbaru menunjukkan React.js dan Node.js memiliki lebih dari 10,000 lowongan di LinkedIn, dan platform Naukri India mencatat 1469 lowongan khusus MERN developer.

Untuk salary, entry-level MERN developers mendapatkan 60,000 hingga 80,000 dollar per tahun, sementara mid-level developer dengan 2-5 tahun pengalaman mendapat 90,000 hingga 120,000 dollar per tahun. Di Indonesia, salary berkisar 3-7 juta rupiah per tahun. Dengan demand yang tinggi, peluang karir MERN developer juga membuka akses ke remote job opportunities dengan salary internasional.

Dalam konteks pembelajaran, ini berarti investasi waktu kamu belajar MERN Stack di BuildWithAngga akan memberikan return yang signifikan dalam peluang kerja dan penghasilan di masa depan.

Digunakan oleh Perusahaan-Perusahaan Besar

Netflix Indonesia - Tonton Acara TV Online, Tonton Film Online
Netflix Indonesia - Tonton Acara TV Online, Tonton Film Online

Kredibilitas teknologi bisa dilihat dari penggunanya. MERN Stack atau komponen-komponennya digunakan oleh tech giants dunia, membuktikan bahwa teknologi ini powerful dan reliable untuk aplikasi skala besar.

Meta (Facebook), Netflix, Airbnb, Dropbox, Walmart, Instagram, PayPal, dan Wix menggunakan React JS untuk aplikasi web dan mobile mereka. Netflix secara strategis menggunakan Node.js sebagai BFF layer dan API Gateway, serta React untuk frontend, yang berhasil mengurangi deployment time dari 40 menit menjadi kurang dari 1 menit dan response time berkurang ~70%. Perusahaan besar seperti NASA, PayPal, Uber, dan Walmart juga menggunakan Node.js dalam production.

Fakta bahwa perusahaan-perusahaan ini menggunakan MERN Stack memberikan confidence tinggi bahwa teknologi ini adalah pilihan yang tepat dan akan tetap relevan di masa depan. Ketika belajar MERN Stack melalui kurikulum BuildWithAngga, kamu sedang belajar teknologi yang sama yang digunakan oleh jutaan developer di perusahaan-perusahaan terbesar dunia.

Learning Curve yang Reasonable untuk Pemula

https://buildwithangga.com/kelas/mern-simple-ecommerce-express-js
https://buildwithangga.com/kelas/mern-simple-ecommerce-express-js

Meskipun MERN Stack adalah teknologi powerful untuk enterprise, learning curve-nya masih reasonable untuk pemula. JavaScript memiliki syntax yang lebih sederhana dibanding Java atau C++. React memiliki dokumentasi excellent dengan contoh code yang mudah diikuti. Ada banyak tutorial gratis berkualitas di YouTube, FreeCodeCamp, dan platform lainnya. Konsep dasar MERN seperti components di React, routes di Express, atau queries di MongoDB relatif mudah dipahami. Development tools modern seperti Create React App atau Vite memberikan instant feedback dengan live reload, membuat learning experience lebih engaging.

Kurikulum BuildWithAngga sudah dioptimasi untuk learning curve yang ideal. Program dirancang progresif mulai dari fundamental JavaScript, HTML, CSS, lalu React, Express, dan MongoDB secara berturut-turut. Setiap section dibangun di atas section sebelumnya tanpa ada gap dalam pembelajaran.

Open-Source dan Terus Berkembang

MERN Stack terdiri dari teknologi open-source yang terus berkembang. Setiap minggu ada update dan improvement dari React, Express, Node.js, atau MongoDB. Update ini tidak hanya menambah fitur baru tetapi juga memperbaiki bug dan meningkatkan performance.

Keuntungan open-source: source code bisa diaudit siapa saja untuk security, membuat vulnerabilities cepat ditemukan dan diperbaiki. Komunitas global berkontribusi dengan membuat library, tool, atau extension untuk MERN Stack, menghasilkan ekosistem yang kaya. Tidak ada vendor lock-in—kamu bebas menggunakan, memodifikasi, atau membuat fork sendiri. Framework seperti React dan Node.js memiliki public roadmap yang transparan sehingga developer bisa planning pembelajaran dengan lebih baik.

Sifat open-source ini berarti MERN Stack tidak akan pernah benar-benar deprecated karena ada komunitas global yang terus maintain dan improve-nya.

Kombinasi Sempurna Membuat Momentum Positif

Demand tinggi di job market memberikan motivasi untuk belajar. Penggunaan oleh perusahaan besar memberikan kredibilitas. Learning curve reasonable membuat orang tidak terancam memulai. Sifat open-source membuat teknologi terus berkembang dan relevant. Kombinasi ini menciptakan siklus positif: semakin banyak orang belajar MERN, semakin banyak resource tersedia, semakin banyak job opportunity terbuka, semakin banyak perusahaan percaya menggunakan teknologi ini.

Sebagai pemula, keputusan belajar MERN Stack adalah wise choice. Kamu tidak hanya belajar teknologi yang populer dan in-demand, tetapi juga teknologi yang akan terus relevant di masa depan. Dengan program pembelajaran di BuildWithAngga, kamu akan mendapatkan semua skill yang diperlukan untuk bersaing di job market dan membangun aplikasi web berkualitas tinggi.

Studi Kasus: Aplikasi Daftar Film Favorit

Saatnya mempraktikkan teori MERN Stack dengan membuat aplikasi nyata. Kita akan membangun "bwa-movie", sebuah aplikasi sederhana yang memungkinkan pengguna melihat daftar film, menambahkan film ke favorit, dan melihat daftar film favorit mereka. Aplikasi ini mencakup hampir semua konsep dasar MERN Stack yang telah dipelajari.

Part 1: Setup Awal

Setup awal adalah fondasi penting sebelum mulai menulis kode. Bagian ini mencakup instalasi tools, membuat struktur folder, dan inisialisasi git repository.

Install Node.js dan npm

Pertama, pastikan Node.js dan npm sudah terinstall. Buka terminal dan jalankan:

node --version
npm --version

Node.js Version
Node.js Version

Jika kedua perintah menampilkan versi, kamu sudah siap. Jika belum, unduh Node.js versi LTS dari nodejs.org. Npm akan terinstall otomatis bersama Node.js.

Setup Folder Project

Buat folder project dengan nama "bwa-movie" dan struktur dasar:

mkdir bwa-movie
cd bwa-movie
mkdir server
mkdir client

Struktur folder akan terlihat seperti ini:

Struktor Foldler
Struktor Foldler

Folder "server" untuk backend (Express dan Node.js), folder "client" untuk frontend (React).

Inisialisasi Git Repository

Git repository harus diinisialisasi di root folder project (folder bwa-movie). Pastikan kamu sudah berada di dalam folder bwa-movie, kemudian jalankan perintah:

git init

Perintah ini akan membuat folder tersembunyi ".git" di dalam folder bwa-movie. Buat file ".gitignore" di folder yang sama dengan konten berikut:

# Dependencies
server/node_modules/
client/node_modules/

# Environment variables
.env
.env.local

# OS files
.DS_Store
Thumbs.db

# Build files
server/dist/
server/build/
client/dist/
client/build/

Setelah itu, buat commit pertama:

git add .
git commit -m "Initial commit: Setup project structure"

Dengan ini, struktur dasar project bwa-movie sudah siap. Di Part 2: Backend (Express + Node.js), kita akan setup folder server, menginstall dependencies untuk backend, dan membuat server pertama dengan Express. Lanjutkan dengan semangat, journey kamu sebagai full-stack developer dengan MERN Stack telah dimulai.

Part 2: Backend (Express + Node.js)

Di bagian ini, kita akan membangun backend untuk aplikasi bwa-movie menggunakan Express v5 dan Node.js. Backend ini akan menangani semua logika bisnis, koneksi ke database, dan menyediakan API yang akan digunakan oleh frontend React. Proses development backend dimulai dari setup folder, instalasi dependencies, hingga membuat koneksi dengan MongoDB.

Catatan Penting: Tutorial ini menggunakan Express v5 (versi terbaru). Pastikan Node.js versi 18 atau lebih tinggi sudah terinstall di komputer kamu, karena Express v5 memerlukan Node.js 18 sebagai minimum requirement.

Buat Folder Backend dan Install Dependencies

Pertama, navigasi ke folder server di dalam project bwa-movie. Buka terminal dan jalankan perintah berikut:

cd bwa-movie/server

Setelah berada di folder server, inisialisasi project Node.js dengan membuat file package.json:

npm init -y

Flag -y akan membuat package.json dengan konfigurasi default tanpa perlu menjawab pertanyaan. Sekarang kita akan menginstall dependencies yang diperlukan untuk backend. Jalankan perintah berikut untuk menginstall Express, Mongoose, dan dotenv:

npm install express mongoose dotenv cors

Berikut penjelasan setiap dependency yang kita install:

  • Express v5 adalah framework web yang digunakan untuk membuat server dan API. Express v5 membawa improvements dalam error handling untuk async middleware dan memiliki performa yang lebih baik.
  • Mongoose adalah library Object Data Modeling untuk MongoDB. Mongoose memudahkan kita untuk berinteraksi dengan MongoDB dan membuat schema untuk data yang kita simpan.
  • dotenv adalah package yang memungkinkan kita untuk menggunakan environment variables dari file .env. File .env akan menyimpan informasi sensitif seperti connection string database.
  • cors adalah middleware untuk menangani Cross-Origin Resource Sharing. Cors diperlukan agar frontend React yang berjalan di port berbeda bisa mengakses API backend tanpa masalah.

Setelah proses instalasi selesai, folder server akan memiliki folder node_modules dan file package.json, package-lock.json yang mencatat semua dependencies yang terinstall.

Setup Server Express Dasar

Sekarang kita akan membuat server Express dasar. Buat file baru bernama "app.js" di folder server dengan konten berikut:

const express = require('express');
const cors = require('cors');
require('dotenv').config();

const app = express();

// Middleware
app.use(cors());
app.use(express.json());

// Routes
app.get('/', (req, res) => {
  res.json({ message: 'Server bwa-movie berjalan dengan baik' });
});

// Error handling middleware (Express v5 improvement)
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).json({ message: 'Terjadi kesalahan di server' });
});

// Start server
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
  console.log(`Server berjalan di port ${PORT}`);
});

Penjelasan kode di atas:

  • require('express') mengimport Express framework
  • require('dotenv').config() memuat environment variables dari file .env
  • app.use(cors()) mengaktifkan CORS middleware untuk menangani request dari domain berbeda
  • app.use(express.json()) membuat Express bisa memproses request dengan format JSON
  • app.get('/') adalah route dasar yang mengembalikan pesan JSON ketika diakses
  • Error handling middleware di Express v5 secara otomatis menangkap rejected promises dari async routes
  • app.listen(PORT) menjalankan server di port yang ditentukan, defaultnya adalah 5000

Untuk menjalankan server, buka terminal di folder server dan jalankan perintah:

node app.js

Jika berhasil, terminal akan menampilkan "Server berjalan di port 5000". Kamu bisa mengakses http://localhost:5000 di browser untuk memastikan server sudah berjalan. Untuk menghentikan server, tekan Ctrl+C di terminal.

Connect ke MongoDB Atlas

MongoDB Atlas adalah layanan cloud database dari MongoDB yang gratis dan mudah digunakan. Kita akan menggunakan MongoDB Atlas untuk menyimpan data film favorit.

Langkah pertama adalah membuat akun di mongodb.com dan membuat cluster baru. Setelah cluster dibuat, kamu akan mendapatkan connection string yang akan digunakan untuk connect ke database.

Buat file ".env" di folder server dengan konten berikut:

PORT=5000
MONGODB_URI=mongodb+srv://[DB_USER]:[DB_PASSWORD]@bwa-movie.wkoxa4x.mongodb.net/?appName=bwa-movie&retryWrites=true&w=majority

Ganti "[DB_USER]" dan "[DB_PASSWORD]" dengan kredensial MongoDB Atlas kamu. Jangan sampai menyimpan file .env ke git repository karena berisi informasi sensitif.

Sekarang update file app.js untuk connect ke MongoDB. Tambahkan kode berikut sebelum app.listen():

const mongoose = require('mongoose');

// Connect to MongoDB
mongoose.connect(process.env.MONGODB_URI)
.then(() => console.log('Connected to MongoDB Atlas'))
.catch((err) => console.log('MongoDB connection error:', err));

Kode ini akan mencoba connect ke MongoDB menggunakan connection string dari .env. Jika berhasil, console akan menampilkan "Connected to MongoDB Atlas". Jika gagal, error akan ditampilkan.

Test API dengan HTTPie

Sebelum melanjutkan ke Part 3, mari kita test apakah API yang sudah kita buat berjalan dengan baik. Asumsi HTTPie sudah terinstall di komputer kamu.

Jalankan server app.js terlebih dahulu di terminal:

node app.js

Buka terminal baru, kemudian test endpoint dasar dengan HTTPie:

http GET <http://localhost:5000/>

Jika berhasil, kamu akan melihat response JSON seperti ini:

Server Berhasil
Server Berhasil

Jika mendapatkan response 200 dengan pesan tersebut, berarti server dan Express app.js sudah berjalan dengan sempurna. Di Part 3 nanti, kita akan menggunakan HTTPie untuk melakukan POST requests menambah data film, GET requests mengambil data, dan operasi lainnya.

Buat Schema Film di Mongoose

Schema adalah blueprint yang mendefinisikan struktur data untuk film di database. Buat folder "models" di dalam folder server, kemudian buat file "Film.js" di dalamnya:

const mongoose = require('mongoose');

const filmSchema = new mongoose.Schema({
  judul: {
    type: String,
    required: true,
  },
  genre: {
    type: String,
    required: true,
  },
  tahun: {
    type: Number,
    required: true,
  },
  rating: {
    type: Number,
    min: 0,
    max: 10,
  },
  createdAt: {
    type: Date,
    default: Date.now,
  },
});

module.exports = mongoose.model('Film', filmSchema);

Penjelasan schema di atas:

  • judul adalah field untuk nama film, tipe String, dan wajib diisi (required: true)
  • genre adalah field untuk genre film, tipe String, dan wajib diisi
  • tahun adalah field untuk tahun rilis, tipe Number, dan wajib diisi
  • rating adalah field untuk rating film (0-10), tipe Number dengan minimum 0 dan maksimum 10
  • createdAt adalah field untuk mencatat kapan data dibuat, otomatis terisi dengan tanggal dan waktu saat ini

Sekarang schema untuk film sudah siap. Di Part 3, kita akan membuat route untuk menambahkan film, mengambil daftar film, dan fitur-fitur lainnya.

Part 3: API Endpoints

Di bagian ini, kita akan membuat semua API endpoints yang diperlukan untuk aplikasi bwa-movie. Endpoints ini akan menangani operasi-operasi dasar seperti menampilkan film, menambah film baru, dan mengelola daftar film favorit. Setiap endpoint akan menggunakan HTTP methods yang sesuai (GET, POST, DELETE) dan mengikuti REST API best practices.

Struktur Folder Routes dan Controllers

Sebelum membuat endpoints, kita akan mengorganisir kode dengan baik menggunakan folder routes dan controllers. Buat struktur folder berikut di dalam folder server:

server/
├── models/
│   └── Film.js
├── routes/
│   └── films.js
├── controllers/
│   └── filmController.js
├── app.js
├── .env
└── package.json

  • Folder routes akan berisi routing logic yang mengarahkan request ke controller yang tepat
  • Folder controllers akan berisi business logic untuk menangani operasi database
  • Folder models sudah ada dari Part 2 berisi schema Film

Buat Film Controller

Controller adalah tempat kita menulis business logic aplikasi. Buat file "filmController.js" di folder controllers dengan konten berikut:

const Film = require('../models/Film');

// GET semua film
exports.getAllFilms = async (req, res) => {
  try {
    const films = await Film.find();
    res.json(films);
  } catch (err) {
    res.status(500).json({ message: err.message });
  }
};

// POST tambah film baru
exports.createFilm = async (req, res) => {
  const film = new Film({
    judul: req.body.judul,
    genre: req.body.genre,
    tahun: req.body.tahun,
    rating: req.body.rating,
  });

  try {
    const newFilm = await film.save();
    res.status(201).json(newFilm);
  } catch (err) {
    res.status(400).json({ message: err.message });
  }
};

// POST tambah film ke favorit
exports.addToFavorite = async (req, res) => {
  try {
    const film = await Film.findById(req.params.id);
    if (!film) {
      return res.status(404).json({ message: 'Film tidak ditemukan' });
    }

    film.isFavorite = true;
    await film.save();
    res.json({ message: 'Film berhasil ditambahkan ke favorit', film });
  } catch (err) {
    res.status(500).json({ message: err.message });
  }
};

// GET semua film favorit
exports.getFavoriteFilms = async (req, res) => {
  try {
    const favoriteFilms = await Film.find({ isFavorite: true });
    res.json(favoriteFilms);
  } catch (err) {
    res.status(500).json({ message: err.message });
  }
};

// DELETE hapus film dari favorit
exports.removeFromFavorite = async (req, res) => {
  try {
    const film = await Film.findById(req.params.id);
    if (!film) {
      return res.status(404).json({ message: 'Film tidak ditemukan' });
    }

    film.isFavorite = false;
    await film.save();
    res.json({ message: 'Film berhasil dihapus dari favorit', film });
  } catch (err) {
    res.status(500).json({ message: err.message });
  }
};

Penjelasan controller di atas:

  • getAllFilms mengambil semua film dari database menggunakan Film.find()
  • createFilm membuat film baru dengan data dari request body dan menyimpannya ke database
  • addToFavorite mencari film berdasarkan ID dan mengubah status isFavorite menjadi true
  • getFavoriteFilms mengambil semua film yang memiliki isFavorite: true
  • removeFromFavorite mencari film berdasarkan ID dan mengubah status isFavorite menjadi false
  • Setiap function menggunakan try-catch untuk menangani error dengan baik

Update Film Schema

Sebelum lanjut membuat routes, kita perlu update schema Film di file models/Film.js untuk menambahkan field isFavorite:

const mongoose = require('mongoose');

const filmSchema = new mongoose.Schema({
  judul: {
    type: String,
    required: true,
  },
  genre: {
    type: String,
    required: true,
  },
  tahun: {
    type: Number,
    required: true,
  },
  rating: {
    type: Number,
    min: 0,
    max: 10,
  },
  isFavorite: {
    type: Boolean,
    default: false,
  },
  createdAt: {
    type: Date,
    default: Date.now,
  },
});

module.exports = mongoose.model('Film', filmSchema);

Field isFavorite akan menyimpan status apakah film adalah favorit atau bukan, dengan default value false.

Buat Film Routes

Routes adalah tempat kita mendefinisikan HTTP endpoints dan menghubungkannya dengan controller. Buat file "films.js" di folder routes dengan konten berikut:

const express = require('express');
const router = express.Router();
const filmController = require('../controllers/filmController');

// GET semua film
router.get('/', filmController.getAllFilms);

// POST tambah film baru
router.post('/', filmController.createFilm);

// GET semua film favorit
router.get('/favorites', filmController.getFavoriteFilms);

// POST tambah film ke favorit
router.post('/:id/favorite', filmController.addToFavorite);

// DELETE hapus film dari favorit
router.delete('/:id/favorite', filmController.removeFromFavorite);

module.exports = router;

Penjelasan routes di atas:

  • router.get('/') mengarahkan GET request ke /films ke function getAllFilms
  • router.post('/') mengarahkan POST request ke /films ke function createFilm
  • router.get('/favorites') mengarahkan GET request ke /films/favorites ke function getFavoriteFilms
  • router.post('/:id/favorite') mengarahkan POST request ke /films/:id/favorite ke function addToFavorite
  • router.delete('/:id/favorite') mengarahkan DELETE request ke /films/:id/favorite ke function removeFromFavorite

Register Routes di app.js

Sekarang kita perlu mendaftarkan routes di file app.js. Tambahkan kode berikut sebelum app.listen():

const filmRoutes = require('./routes/films');

// Routes
app.use('/api/films', filmRoutes);

Dengan ini, semua endpoint films akan dapat diakses melalui path /api/films.

Test Endpoints dengan HTTPie

Sekarang mari kita test semua endpoints yang telah kita buat. Pastikan server app.js sudah berjalan. Buka terminal baru dan jalankan command berikut untuk setiap endpoint.

GET semua film:

http GET <http://localhost:5000/api/films>

Response yang diharapkan (200 OK):

[]

Awalnya akan kosong karena belum ada film yang ditambahkan.

POST tambah film baru:

http POST <http://localhost:5000/api/films> judul="Inception" genre="Sci-Fi" tahun=2010 rating=8.8

Response yang diharapkan (201 Created):

Test API: Buat Film
Test API: Buat Film

Catat _id dari response karena akan digunakan untuk endpoint berikutnya.

POST tambah film ke favorit:

http POST <http://localhost:5000/api/films/[FILM_ID]/favorite>

Ganti [FILM_ID] dengan ID yang didapat dari response sebelumnya. Response yang diharapkan (200 OK):

Test API: Tambahkan Film ke Favorite
Test API: Tambahkan Film ke Favorite

GET semua film favorit:

http GET <http://localhost:5000/api/films/favorites>

Response yang diharapkan (200 OK):

Test API: Daftar Film Favorites
Test API: Daftar Film Favorites

DELETE hapus film dari favorit:

http DELETE <http://localhost:5000/api/films/[FILM_ID]/favorite>

Ganti [FILM_ID] dengan ID film yang ingin dihapus dari favorit. Response yang diharapkan (200 OK):

Test API: Hapus Film dari Favorite
Test API: Hapus Film dari Favorite

Penjelasan HTTP Status Codes

Dalam API yang kita buat, kita menggunakan HTTP status codes yang sesuai untuk setiap situasi:

  • 200 OK digunakan ketika request berhasil dan ada data yang dikembalikan
  • 201 Created digunakan ketika resource baru berhasil dibuat
  • 400 Bad Request digunakan ketika ada error di sisi client, misalnya data yang dikirim tidak valid
  • 404 Not Found digunakan ketika resource yang diminta tidak ditemukan
  • 500 Internal Server Error digunakan ketika ada error di sisi server

Dengan menggunakan status codes yang benar, frontend bisa dengan mudah mengetahui status dari setiap request yang dikirim.

Sekarang backend untuk aplikasi bwa-movie sudah lengkap dengan semua endpoints yang diperlukan. Di Part 4 nanti, kita akan membuat frontend dengan React untuk mengkonsumsi API-API yang telah kita buat.

Part 4: Frontend dengan React

Sejauh ini, kita sudah membangun backend yang solid dengan Express, Node.js, dan MongoDB untuk aplikasi bwa-movie. Sekarang saatnya untuk membuat bagian yang paling banyak dilihat oleh pengguna: frontend dengan React. Jika backend adalah otak dari aplikasi, maka React adalah wajah yang cantik dan responsif yang membuat pengguna betah berlama-lama menggunakan aplikasi kita.

Pada bagian ini, kita akan belajar membuat antarmuka pengguna yang interaktif untuk aplikasi bwa-movie. Kita akan membuat beberapa halaman, beberapa komponen, dan menghubungkan semuanya sehingga terlihat seperti aplikasi yang sungguh-sungguhan. Jangan khawatir jika ada yang tidak langsung mengerti, karena di BuildWithAngga kita akan membahas setiap konsep dengan detail dan jelas.

Setup React dengan React Router

Langkah pertama adalah membuat proyek React baru di dalam folder client di dalam project bwa-movie. React Router adalah framework yang direkomendasikan oleh React resmi untuk membuat aplikasi React modern. Navigasi ke folder client terlebih dahulu, kemudian jalankan perintah berikut untuk membuat proyek React dengan React Router:

cd bwa-movie/client
npx create-react-router@latest .

Perintah pertama akan membawa kamu masuk ke dalam folder client. Perintah kedua akan membuat proyek React Router Framework langsung di dalam folder client tersebut (perhatikan tanda titik . yang berarti "di folder saat ini"). Proses instalasi ini mungkin memakan waktu beberapa menit, jadi bersabarlah sampai selesai.

Setelah selesai, folder client akan sudah memiliki semua struktur yang diperlukan termasuk routing configuration. React Router menyediakan template yang sudah dikonfigurasi dengan baik untuk memulai proyek.

Setelah selesai, struktur folder project bwa-movie kamu akan terlihat seperti ini:

bwa-movie/
├── server/                 (backend Express yang sudah kita buat)
│   ├── models/
│   ├── routes/
│   ├── controllers/
│   ├── app.js
│   ├── .env
│   └── package.json
└── client/                 (frontend React Router yang baru)
    ├── app/               (folder utama aplikasi React Router)
    │   ├── routes/        (folder untuk route-based components)
    │   ├── root.tsx       (root layout aplikasi)
    │   └── routes.ts      (konfigurasi routes)
    ├── public/            (file statis)
    ├── node_modules/      (semua library yang diinstal)
    ├── package.json       (konfigurasi proyek dan dependensi)
    ├── vite.config.ts     (konfigurasi Vite build tool)
    └── react-router.config.ts

Struktur ini sangat bagus karena memisahkan backend dan frontend dalam folder terpisah. Folder app/ adalah pusat dari aplikasi React Router kamu, yang berisi semua route-based components dan konfigurasi routing. Kamu bisa menjalankan keduanya secara bersamaan di terminal yang berbeda.

Sekarang kita perlu menambahkan Axios untuk melakukan HTTP request ke backend API kita. React Router sudah menyediakan routing built-in, jadi kita hanya perlu install Axios. Pastikan kamu masih berada di folder client, kemudian jalankan perintah berikut:

npm install axios

Tunggu hingga proses instalasi selesai. Sekarang proyek React kamu sudah siap untuk dikembangkan lebih lanjut dengan React Router Framework yang powerful.

Menjalankan Aplikasi React Router

Untuk menjalankan aplikasi React Router kamu, pastikan kamu berada di folder client, kemudian jalankan perintah berikut:

npm run dev

Tampilan Awal React Router
Tampilan Awal React Router

Aplikasi React akan membuka di browser secara otomatis di http://localhost:5173. React Router menggunakan Vite sebagai build tool, yang jauh lebih cepat dibanding Create React App karena menggunakan esbuild di bawah hoodnya.

Membuat Struktur Folder untuk Komponen dan Services

Sebelum kita mulai menulis kode, kita perlu menambahkan beberapa folder untuk mengorganisir komponen dan service API kita dengan baik. Ini adalah praktik terbaik dalam pengembangan React yang akan membuat kode lebih mudah dikelola dan dipahami oleh tim atau developer lain di masa depan.

React Router sudah menyediakan folder app/routes/ untuk route-based components. Sekarang kita akan menambahkan folder app/components/ untuk komponen yang dapat digunakan ulang, dan app/services/ untuk API communication logic.

Di dalam folder app, buatlah beberapa folder baru seperti ini:

client/app/
├── components/         (komponen yang dapat digunakan ulang)
│   ├── FilmCard.tsx
│   ├── FilmCard.css
│   ├── FilmList.tsx
│   ├── FilmList.css
│   ├── FavoriteList.tsx
│   ├── FavoriteList.css
│   ├── Navbar.tsx
│   └── Navbar.css
├── routes/            (route-based pages)
│   ├── home.tsx
│   ├── home.css
│   ├── favorites.tsx
│   ├── favorites.css
│   └── _index.tsx
├── services/          (layanan untuk berkomunikasi dengan API)
│   └── filmService.ts
├── root.tsx           (root layout aplikasi)
├── root.css           (styling untuk root layout)
├── routes.ts          (konfigurasi routes)
└── entry.client.tsx

Mari kita buat folder-folder ini. Di terminal, pastikan kamu berada di dalam folder app, kemudian jalankan perintah berikut:

mkdir components services

Bagus! Sekarang kita memiliki struktur folder yang rapi dan terorganisir dengan baik. Mari kita mulai membuat service untuk berkomunikasi dengan backend.

Membuat Film Service untuk API Communication

Sebelum kita membuat komponen, kita perlu membuat sebuah service yang akan menangani semua komunikasi dengan backend API. Service ini akan memuat semua fungsi untuk GET, POST, DELETE, dan operasi API lainnya.

Buatlah file baru bernama filmService.ts di dalam folder services. Isikan dengan kode berikut:

import axios from "axios";

const API_BASE_URL = "<http://localhost:5000/api/films>";

// Fungsi untuk mendapatkan semua film
export const getAllFilms = async () => {
  try {
    const response = await axios.get(API_BASE_URL);
    return response.data;
  } catch (error) {
    console.error("Error fetching films:", error);
    throw error;
  }
};

// Fungsi untuk membuat film baru
export const createFilm = async (filmData: any) => {
  try {
    const response = await axios.post(API_BASE_URL, filmData);
    return response.data;
  } catch (error) {
    console.error("Error creating film:", error);
    throw error;
  }
};

// Fungsi untuk mendapatkan semua film favorit
export const getFavoriteFilms = async () => {
  try {
    const response = await axios.get(`${API_BASE_URL}/favorites`);
    return response.data;
  } catch (error) {
    console.error("Error fetching favorite films:", error);
    throw error;
  }
};

// Fungsi untuk menambah film ke favorit
export const addToFavorite = async (filmId: string) => {
  try {
    const response = await axios.post(`${API_BASE_URL}/${filmId}/favorite`);
    return response.data;
  } catch (error) {
    console.error("Error adding film to favorite:", error);
    throw error;
  }
};

// Fungsi untuk menghapus film dari favorit
export const removeFromFavorite = async (filmId: string) => {
  try {
    const response = await axios.delete(`${API_BASE_URL}/${filmId}/favorite`);
    return response.data;
  } catch (error) {
    console.error("Error removing film from favorite:", error);
    throw error;
  }
};

Service ini berfungsi sebagai "jembatan" antara komponen React kita dan backend API. Dengan memisahkan logika API ke dalam service tersendir, kita membuat kode lebih bersih dan lebih mudah untuk di-test atau di-maintain di masa depan.

Perhatikan bahwa kita menggunakan async/await untuk menangani operasi asinkron. Ini memastikan bahwa kode kita menunggu sampai respons dari server diterima sebelum melanjutkan ke operasi berikutnya. Ini adalah best practice modern dalam menangani Promise di JavaScript.

Membuat Komponen FilmCard

Sekarang kita akan membuat komponen pertama kita: FilmCard. Komponen ini akan menampilkan sebuah kartu film yang berisi informasi dasar tentang film tersebut, seperti judul, genre, tahun rilis, dan rating.

Buatlah file baru bernama FilmCard.tsx di dalam folder components. Isikan dengan kode berikut:

import React from "react";
import "./FilmCard.css";

interface Film {
  _id: string;
  judul: string;
  genre: string;
  tahun: number;
  rating: number;
  deskripsi?: string;
}

interface FilmCardProps {
  film: Film;
  onFavoriteToggle: (filmId: string) => void;
  isFavorite: boolean;
}

const FilmCard: React.FC<FilmCardProps> = ({ film, onFavoriteToggle, isFavorite }) => {
  return (
    <div className="film-card">
      <div className="film-card-header">
        <h3 className="film-title">{film.judul}</h3>
        <button
          className={`favorite-btn ${isFavorite ? "active" : ""}`}
          onClick={() => onFavoriteToggle(film._id)}
          title={isFavorite ? "Hapus dari favorit" : "Tambah ke favorit"}
        >
          {isFavorite ? "★" : "☆"}
        </button>
      </div>

      <div className="film-details">
        <p className="film-genre">
          <strong>Genre:</strong> {film.genre}
        </p>
        <p className="film-year">
          <strong>Tahun:</strong> {film.tahun}
        </p>
        <p className="film-rating">
          <strong>Rating:</strong> {film.rating}/10
        </p>
      </div>

      <div className="film-description">
        {film.deskripsi && <p>{film.deskripsi}</p>}
      </div>
    </div>
  );
};

export default FilmCard;

Komponen FilmCard ini menerima tiga props: film (data film dari API), onFavoriteToggle (fungsi untuk menambah atau menghapus dari favorit), dan isFavorite (status apakah film sudah di-favorit atau belom). Perhatikan penggunaan TypeScript interface untuk tipe-tipe data, yang memberikan better type safety dan autocomplete di IDE kamu.

Perhatikan penggunaan kondisional untuk menampilkan bintang (★ untuk favorit, ☆ untuk bukan favorit). Ini memberikan umpan balik visual yang jelas kepada pengguna tentang status favorit film tersebut.

Sekarang buatlah file CSS untuk komponen ini. Buat file FilmCard.css di folder components:

.film-card {
  border: 1px solid #ddd;
  border-radius: 8px;
  padding: 16px;
  margin-bottom: 16px;
  background-color: #fff;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  transition: transform 0.2s, box-shadow 0.2s;
}

.film-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
}

.film-card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 12px;
  border-bottom: 2px solid #f0f0f0;
  padding-bottom: 12px;
}

.film-title {
  margin: 0;
  font-size: 20px;
  color: #333;
  flex: 1;
}

.favorite-btn {
  background: none;
  border: none;
  font-size: 24px;
  cursor: pointer;
  color: #ccc;
  transition: color 0.3s;
  padding: 0;
  margin-left: 12px;
}

.favorite-btn:hover {
  color: #ffc107;
}

.favorite-btn.active {
  color: #ffc107;
}

.film-details {
  margin-bottom: 12px;
  background-color: #f9f9f9;
  padding: 12px;
  border-radius: 4px;
}

.film-details p {
  margin: 6px 0;
  font-size: 14px;
  color: #555;
}

.film-genre,
.film-year,
.film-rating {
  margin: 4px 0;
}

.film-description {
  color: #666;
  font-size: 14px;
  line-height: 1.5;
}

.film-description p {
  margin: 8px 0;
}

Membuat Komponen FilmList

Selanjutnya, kita akan membuat komponen FilmList yang menampilkan daftar semua film dalam bentuk beberapa kartu film. Komponen ini akan menggunakan FilmCard yang sudah kita buat sebelumnya.

Daftar Film
Daftar Film

Buatlah file FilmList.tsx di folder components:

import React from "react";
import FilmCard from "./FilmCard";
import "./FilmList.css";

interface Film {
  _id: string;
  judul: string;
  genre: string;
  tahun: number;
  rating: number;
  deskripsi?: string;
}

interface FilmListProps {
  films: Film[];
  favoriteIds: string[];
  onFavoriteToggle: (filmId: string) => void;
}

const FilmList: React.FC<FilmListProps> = ({ films, favoriteIds, onFavoriteToggle }) => {
  if (!films || films.length === 0) {
    return (
      <div className="empty-state">
        <p>Tidak ada film untuk ditampiilkan. Mulai tambahkan film baru!</p>
      </div>
    );
  }

  return (
    <div className="film-list">
      <div className="film-list-header">
        <h2>Daftar Film</h2>
        <span className="film-count">Total: {films.length} film</span>
      </div>

      <div className="film-grid">
        {films.map((film) => (
          <FilmCard
            key={film._id}
            film={film}
            onFavoriteToggle={onFavoriteToggle}
            isFavorite={favoriteIds.includes(film._id)}
          />
        ))}
      </div>
    </div>
  );
};

export default FilmList;

Komponen FilmList menggunakan .map() untuk mengubah array film menjadi array komponen FilmCard. Untuk setiap film, kita cek apakah ID film tersebut ada dalam array favoriteIds untuk menentukan apakah tombol favorit harus ditampilkan dalam status aktif atau tidak.

Buat file CSS-nya FilmList.css:

.film-list {
  padding: 20px;
  background-color: #fff;
  border-radius: 8px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}

.film-list-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 24px;
  padding-bottom: 16px;
  border-bottom: 2px solid #eee;
}

.film-list-header h2 {
  margin: 0;
  font-size: 28px;
  color: #333;
}

.film-count {
  font-size: 14px;
  color: #888;
  background-color: #f5f5f5;
  padding: 6px 12px;
  border-radius: 20px;
}

.film-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
}

@media (min-width: 768px) {
  .film-grid {
    grid-template-columns: 1fr 1fr;
  }
}

@media (min-width: 1024px) {
  .film-grid {
    grid-template-columns: 1fr 1fr 1fr;
  }
}

.empty-state {
  padding: 40px 20px;
  text-align: center;
  background-color: #f9f9f9;
  border-radius: 8px;
  color: #666;
  font-size: 16px;
}

.empty-state p {
  margin: 0;
}

Membuat Komponen FavoriteList

Sekarang kita akan membuat komponen FavoriteList yang mirip dengan FilmList, tetapi hanya menampilkan film-film yang sudah ditambahkan ke favorit.

Film Favorit
Film Favorit

Buatlah file FavoriteList.tsx di folder components:

import React from "react";
import FilmCard from "./FilmCard";
import "./FavoriteList.css";

interface Film {
  _id: string;
  judul: string;
  genre: string;
  tahun: number;
  rating: number;
  deskripsi?: string;
}

interface FavoriteListProps {
  favoriteFilms: Film[];
  onFavoriteToggle: (filmId: string) => void;
}

const FavoriteList: React.FC<FavoriteListProps> = ({ favoriteFilms, onFavoriteToggle }) => {
  if (!favoriteFilms || favoriteFilms.length === 0) {
    return (
      <div className="empty-favorite-state">
        <div className="empty-icon">☆</div>
        <p className="empty-message">
          Kamu belum menambahkan film ke favorit. Jelajahi dan tambahkan film
          favorit kamu sekarang!
        </p>
      </div>
    );
  }

  return (
    <div className="favorite-list">
      <div className="favorite-list-header">
        <h2>Film Favorit Kamu</h2>
        <span className="favorite-count">
          ★ {favoriteFilms.length} film
        </span>
      </div>

      <div className="favorite-grid">
        {favoriteFilms.map((film) => (
          <FilmCard
            key={film._id}
            film={film}
            onFavoriteToggle={onFavoriteToggle}
            isFavorite={true}
          />
        ))}
      </div>
    </div>
  );
};

export default FavoriteList;

Buat file CSS-nya FavoriteList.css:

.favorite-list {
  padding: 20px;
  background-color: #fff;
  border-radius: 8px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}

.favorite-list-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 24px;
  padding-bottom: 16px;
  border-bottom: 3px solid #ffc107;
}

.favorite-list-header h2 {
  margin: 0;
  font-size: 28px;
  color: #333;
}

.favorite-count {
  font-size: 16px;
  color: #ffc107;
  background-color: #fff8e1;
  padding: 8px 16px;
  border-radius: 20px;
  font-weight: 600;
}

.favorite-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
}

@media (min-width: 768px) {
  .favorite-grid {
    grid-template-columns: 1fr 1fr;
  }
}

@media (min-width: 1024px) {
  .favorite-grid {
    grid-template-columns: 1fr 1fr 1fr;
  }
}

.empty-favorite-state {
  padding: 60px 20px;
  text-align: center;
  background: linear-gradient(135deg, #fff8e1 0%, #fffef0 100%);
  border-radius: 8px;
  border: 2px dashed #ffc107;
}

.empty-icon {
  font-size: 64px;
  margin-bottom: 16px;
  opacity: 0.5;
}

.empty-message {
  margin: 0;
  color: #555;
  font-size: 16px;
  line-height: 1.6;
}

Perhatikan bahwa komponen FavoriteList selalu mengirim isFavorite={true} ke FilmCard, karena film yang ditampiilkan di sini adalah film yang sudah difavoritkan.

Membuat Route Home

Sekarang mari kita buat route pertama kita: halaman utama aplikasi. Halaman ini akan menampilkan daftar semua film dan memungkinkan pengguna untuk menambah film baru.

Halaman Home
Halaman Home

Buatlah file home.tsx di dalam folder routes:

import React, { useState, useEffect } from "react";
import FilmList from "../components/FilmList";
import {
  getAllFilms,
  createFilm,
  getFavoriteFilms,
  addToFavorite,
  removeFromFavorite,
} from "../services/filmService";
import "./home.css";

interface Film {
  _id: string;
  judul: string;
  genre: string;
  tahun: number;
  rating: number;
  deskripsi?: string;
}

export default function Home() {
  const [films, setFilms] = useState<Film[]>([]);
  const [favoriteIds, setFavoriteIds] = useState<string[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [showForm, setShowForm] = useState(false);
  const [formData, setFormData] = useState({
    judul: "",
    genre: "",
    tahun: new Date().getFullYear(),
    rating: 0,
    deskripsi: "",
  });

  // Fetch semua film saat komponen pertama kali di-load
  useEffect(() => {
    loadFilms();
    loadFavorites();
  }, []);

  const loadFilms = async () => {
    try {
      setLoading(true);
      const data = await getAllFilms();
      setFilms(data);
      setError(null);
    } catch (err) {
      setError("Gagal memuat data film. Silakan coba lagi.");
      console.error(err);
    } finally {
      setLoading(false);
    }
  };

  const loadFavorites = async () => {
    try {
      const favoriteData = await getFavoriteFilms();
      const favoriteIdsList = favoriteData.map((film: Film) => film._id);
      setFavoriteIds(favoriteIdsList);
    } catch (err) {
      console.error("Gagal memuat data favorit:", err);
    }
  };

  const handleAddFilm = async (e: React.FormEvent) => {
    e.preventDefault();

    // Validasi dasar
    if (!formData.judul || !formData.genre) {
      alert("Judul dan genre harus diisi!");
      return;
    }

    try {
      const newFilm = {
        judul: formData.judul,
        genre: formData.genre,
        tahun: parseInt(String(formData.tahun)),
        rating: parseFloat(String(formData.rating)),
        deskripsi: formData.deskripsi,
      };

      await createFilm(newFilm);

      // Reset form dan refresh data
      setFormData({
        judul: "",
        genre: "",
        tahun: new Date().getFullYear(),
        rating: 0,
        deskripsi: "",
      });
      setShowForm(false);

      // Reload film list
      await loadFilms();
    } catch (err) {
      alert("Gagal menambahkan film. Silakan coba lagi.");
      console.error(err);
    }
  };

  const handleFavoriteToggle = async (filmId: string) => {
    try {
      if (favoriteIds.includes(filmId)) {
        // Hapus dari favorit
        await removeFromFavorite(filmId);
        setFavoriteIds(favoriteIds.filter((id) => id !== filmId));
      } else {
        // Tambah ke favorit
        await addToFavorite(filmId);
        setFavoriteIds([...favoriteIds, filmId]);
      }
    } catch (err) {
      alert("Gagal mengubah status favorit. Silakan coba lagi.");
      console.error(err);
    }
  };

  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
    const { name, value } = e.currentTarget;
    setFormData({
      ...formData,
      [name]: value,
    });
  };

  if (loading) {
    return <div className="loading">Memuat data film...</div>;
  }

  return (
    <div className="home-page">
      <div className="home-header">
        <h1>Koleksi Film BuildWithAngga</h1>
        <p className="home-subtitle">
          Temukan, tandai, dan nikmati film-film favorit kamu
        </p>
      </div>

      {error && <div className="error-message">{error}</div>}

      <div className="add-film-section">
        <button
          className="add-film-btn"
          onClick={() => setShowForm(!showForm)}
        >
          {showForm ? "Tutup Form" : "+ Tambah Film Baru"}
        </button>

        {showForm && (
          <form className="add-film-form" onSubmit={handleAddFilm}>
            <div className="form-group">
              <label htmlFor="judul">Judul Film</label>
              <input
                id="judul"
                type="text"
                name="judul"
                value={formData.judul}
                onChange={handleInputChange}
                placeholder="Masukkan judul film..."
                required
              />
            </div>

            <div className="form-row">
              <div className="form-group">
                <label htmlFor="genre">Genre</label>
                <input
                  id="genre"
                  type="text"
                  name="genre"
                  value={formData.genre}
                  onChange={handleInputChange}
                  placeholder="Contoh: Drama, Action, Comedy"
                  required
                />
              </div>

              <div className="form-group">
                <label htmlFor="tahun">Tahun</label>
                <input
                  id="tahun"
                  type="number"
                  name="tahun"
                  value={formData.tahun}
                  onChange={handleInputChange}
                  min="1900"
                  max={new Date().getFullYear()}
                />
              </div>

              <div className="form-group">
                <label htmlFor="rating">Rating</label>
                <input
                  id="rating"
                  type="number"
                  name="rating"
                  value={formData.rating}
                  onChange={handleInputChange}
                  min="0"
                  max="10"
                  step="0.1"
                />
              </div>
            </div>

            <div className="form-group">
              <label htmlFor="deskripsi">Deskripsi (Opsional)</label>
              <textarea
                id="deskripsi"
                name="deskripsi"
                value={formData.deskripsi}
                onChange={handleInputChange}
                placeholder="Tuliskan deskripsi singkat tentang film ini..."
                rows={3}
              />
            </div>

            <button type="submit" className="form-submit-btn">
              Simpan Film
            </button>
          </form>
        )}
      </div>

      <FilmList
        films={films}
        favoriteIds={favoriteIds}
        onFavoriteToggle={handleFavoriteToggle}
      />
    </div>
  );
}

Halaman Home ini mengelola state untuk daftar film, favorit, dan form tambah film. Perhatikan penggunaan useEffect untuk memuat data saat komponen pertama kali di-mount. Ini adalah pola umum dalam React untuk menangani side effects seperti fetching data dari API.

Buat file CSS untuk halaman Home, home.css:

.home-page {
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;
}

.home-header {
  text-align: center;
  margin-bottom: 40px;
  padding: 30px 20px;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  border-radius: 12px;
}

.home-header h1 {
  margin: 0 0 10px 0;
  font-size: 36px;
}

.home-subtitle {
  margin: 0;
  font-size: 16px;
  opacity: 0.9;
}

.error-message {
  background-color: #fee;
  color: #c33;
  padding: 12px 16px;
  border-radius: 4px;
  margin-bottom: 20px;
  border-left: 4px solid #c33;
}

.loading {
  text-align: center;
  padding: 40px;
  font-size: 18px;
  color: #666;
}

.add-film-section {
  margin-bottom: 30px;
  background-color: #f9f9f9;
  padding: 20px;
  border-radius: 8px;
}

.add-film-btn {
  background-color: #667eea;
  color: white;
  border: none;
  padding: 12px 24px;
  border-radius: 6px;
  font-size: 16px;
  cursor: pointer;
  transition: background-color 0.3s;
  font-weight: 600;
}

.add-film-btn:hover {
  background-color: #5568d3;
}

.add-film-form {
  margin-top: 20px;
  background-color: white;
  padding: 20px;
  border-radius: 8px;
  border: 1px solid #ddd;
}

.form-group {
  margin-bottom: 16px;
}

.form-group label {
  display: block;
  margin-bottom: 6px;
  font-weight: 600;
  color: #333;
  font-size: 14px;
}

.form-group input,
.form-group textarea {
  width: 100%;
  padding: 10px;
  border: 1px solid #ddd;
  border-radius: 4px;
  font-size: 14px;
  font-family: inherit;
  box-sizing: border-box;
}

.form-group input:focus,
.form-group textarea:focus {
  outline: none;
  border-color: #667eea;
  box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}

.form-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
}

@media (min-width: 768px) {
  .form-row {
    grid-template-columns: 2fr 1fr 1fr;
  }
}

.form-submit-btn {
  background-color: #48bb78;
  color: white;
  border: none;
  padding: 12px 32px;
  border-radius: 6px;
  font-size: 16px;
  cursor: pointer;
  font-weight: 600;
  transition: background-color 0.3s;
  width: 100%;
}

.form-submit-btn:hover {
  background-color: #38a169;
}

Membuat Route Favorites

Sekarang kita akan membuat halaman khusus untuk menampilkan film-film favorit pengguna.

Halaman Favorit
Halaman Favorit

Buatlah file favorites.tsx di folder routes:

import React, { useState, useEffect } from "react";
import FavoriteList from "../components/FavoriteList";
import {
  getFavoriteFilms,
  removeFromFavorite,
} from "../services/filmService";
import "./favorites.css";

interface Film {
  _id: string;
  judul: string;
  genre: string;
  tahun: number;
  rating: number;
  deskripsi?: string;
}

export default function Favorites() {
  const [favoriteFilms, setFavoriteFilms] = useState<Film[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    loadFavoriteFilms();
  }, []);

  const loadFavoriteFilms = async () => {
    try {
      setLoading(true);
      const data = await getFavoriteFilms();
      setFavoriteFilms(data);
      setError(null);
    } catch (err) {
      setError("Gagal memuat film favorit. Silakan coba lagi.");
      console.error(err);
    } finally {
      setLoading(false);
    }
  };

  const handleRemoveFromFavorite = async (filmId: string) => {
    try {
      await removeFromFavorite(filmId);
      // Hapus film dari list lokal
      setFavoriteFilms(favoriteFilms.filter((film) => film._id !== filmId));
    } catch (err) {
      alert("Gagal menghapus dari favorit. Silakan coba lagi.");
      console.error(err);
    }
  };

  if (loading) {
    return <div className="loading">Memuat film favorit kamu...</div>;
  }

  return (
    <div className="favorites-page">
      <div className="favorites-header">
        <h1>Daftar Film Favorit Kamu</h1>
        <p className="favorites-subtitle">
          Kelola koleksi pribadi film-film terbaik kamu
        </p>
      </div>

      {error && <div className="error-message">{error}</div>}

      <FavoriteList
        favoriteFilms={favoriteFilms}
        onFavoriteToggle={handleRemoveFromFavorite}
      />
    </div>
  );
}

Buat file CSS untuk halaman Favorites, favorites.css:

.favorites-page {
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;
}

.favorites-header {
  text-align: center;
  margin-bottom: 40px;
  padding: 30px 20px;
  background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
  color: white;
  border-radius: 12px;
}

.favorites-header h1 {
  margin: 0 0 10px 0;
  font-size: 36px;
}

.favorites-subtitle {
  margin: 0;
  font-size: 16px;
  opacity: 0.9;
}

.error-message {
  background-color: #fee;
  color: #c33;
  padding: 12px 16px;
  border-radius: 4px;
  margin-bottom: 20px;
  border-left: 4px solid #c33;
}

.loading {
  text-align: center;
  padding: 40px;
  font-size: 18px;
  color: #666;
}

Membuat Komponen Navbar untuk Navigasi

Sebelum kita menghubungkan semuanya dalam aplikasi utama, mari kita buat komponen Navbar yang akan memudahkan pengguna untuk menavigasi antara halaman Home dan Favorites.

Buatlah file Navbar.tsx di folder components:

import React from "react";
import { Link } from "react-router";
import "./Navbar.css";

export default function Navbar() {
  return (
    <nav className="navbar">
      <div className="navbar-container">
        <Link to="/" className="navbar-logo">
          BuildWithAngga Movie
        </Link>

        <ul className="nav-menu">
          <li className="nav-item">
            <Link to="/" className="nav-link">
              Semua Film
            </Link>
          </li>
          <li className="nav-item">
            <Link to="/favorites" className="nav-link">
              ★ Favorit
            </Link>
          </li>
        </ul>
      </div>
    </nav>
  );
}

Perhatikan bahwa kita menggunakan react-router bukan react-router-dom karena React Router v7 sudah menyatukan semuanya dalam satu package.

Buat file CSS untuk Navbar, Navbar.css:

.navbar {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  padding: 0;
  position: sticky;
  top: 0;
  z-index: 100;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.navbar-container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 16px 20px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.navbar-logo {
  font-size: 24px;
  font-weight: 700;
  color: white;
  text-decoration: none;
  cursor: pointer;
}

.navbar-logo:hover {
  opacity: 0.9;
}

.nav-menu {
  display: flex;
  list-style: none;
  margin: 0;
  padding: 0;
  gap: 30px;
}

.nav-item {
  margin: 0;
}

.nav-link {
  color: white;
  text-decoration: none;
  font-weight: 500;
  transition: opacity 0.3s;
  font-size: 16px;
}

.nav-link:hover {
  opacity: 0.8;
}

@media (max-width: 768px) {
  .navbar-container {
    flex-direction: column;
    gap: 12px;
  }

  .nav-menu {
    gap: 20px;
  }
}

Konfigurasi Routes dan Root Layout

Sekarang saatnya untuk mengkonfigurasi routing dan root layout aplikasi React Router kita. React Router v7 menggunakan file-based routing yang lebih modern dan powerful.

Pertama, mari kita setup file root.tsx yang merupakan root layout aplikasi. File ini sudah ada, jadi kita tinggal update saja:

import { Outlet, Scripts } from "react-router";
import Navbar from "./components/Navbar";
import "./root.css";

export default function Root() {
  return (
    <html>
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <title>BuildWithAngga Movie</title>
      </head>
      <body>
        <Navbar />
        <main className="main-content">
          <Outlet />
        </main>
        <Scripts />
      </body>
    </html>
  );
}

Sekarang, mari kita setup file routes.ts yang mendefinisikan struktur routing aplikasi kita:

import { type RouteConfig, index, route } from "@react-router/dev/routes";

export default [
  index("routes/home.tsx"),
  route("favorites", "routes/favorites.tsx"),
] satisfies RouteConfig;

File ini mendefinisikan dua route: route index (halaman utama /) yang mengarah ke home.tsx, dan route /favorites yang mengarah ke favorites.tsx.

Buat file CSS untuk root, root.css:

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html,
body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
    "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans",
    "Helvetica Neue", sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  background-color: #f5f7fa;
  color: #333;
}

.main-content {
  min-height: calc(100vh - 60px);
  padding: 20px;
}

Menjalankan Aplikasi React Router

Sekarang mari kita jalankan aplikasi React Router kita untuk melihat hasilnya. Pastikan backend API kamu sudah berjalan di localhost:5000 terlebih dahulu, kemudian jalankan perintah berikut di terminal (pastikan kamu berada di folder client):

npm run dev

Aplikasi React akan membuka di browser secara otomatis di http://localhost:5173. Kamu sekarang memiliki aplikasi MERN Stack yang fungsional dengan fitur-fitur berikut:

  • Menampilkan daftar semua film dari backend API dengan sempurna
  • Menambah film baru melalui form yang user-friendly
  • Menandai film sebagai favorit atau menghapusnya dari favorit dengan mudah
  • Halaman khusus untuk melihat film-film favorit kamu
  • Navigasi yang mudah antara halaman dengan React Router v7
  • Tampilan yang responsif dan menaik di berbagai ukuran layar

Beberapa hal penting yang sudah kita lakukan di Part 4 ini sangat berharga untuk karir developer kamu:

Pertama, kita memisahkan logika API ke dalam services folder. Ini membuat kode lebih modular dan mudah di-test. Jika suatu saat kita perlu mengubah endpoint API, kita hanya perlu mengubahnya di satu tempat saja.

Kedua, kita membuat komponen yang reusable dan modular. FilmCard dapat digunakan oleh komponen lain tanpa perlu mengubah kodenya. Ini adalah prinsip DRY (Don't Repeat Yourself) dalam tindakan nyata.

Ketiga, kita menggunakan hooks seperti useState dan useEffect untuk mengelola state dan side effects. Ini adalah pola modern dalam React yang membuat kode lebih clean dan mudah dipahami.

Keempat, kita menggunakan React Router untuk mengelola navigasi antar halaman tanpa perlu reload halaman secara keseluruhan. Ini memberikan pengalaman pengguna yang lebih baik dan lebih responsif.

Kesimpulan & Next Steps: Memulai Perjalanan MERN Stack Kamu

Kamu sudah menguasai teori lengkap tentang MERN Stack. Sekarang saatnya ambil tindakan nyata untuk memulai karier developer yang cemerlang.

MERN Stack Adalah Pilihan yang Tepat

MERN Stack ideal untuk membangun aplikasi web modern. Permintaan developer dengan skill MERN sangat tinggi di pasar kerja saat ini. Dengan menguasai stack ini, kamu tidak hanya mendapatkan pekerjaan, tetapi bisa memilih pekerjaan sesuai karir goals kamu. Income yang kompetitif menanti, baik sebagai karyawan tetap maupun freelancer.

Rekomendasi: Belajar di BuildWithAngga

Untuk memastikan kamu belajar dengan struktur yang tepat dan kurikulum relevan dengan industri, kami sangat merekomendasikan BuildWithAngga. Tim instruktur kami terdiri dari developer berpengalaman yang sudah bekerja di perusahaan teknologi ternama. Kurikulum dirancang berdasarkan kebutuhan industri terkini, bukan hanya teori abstrak.

BuildWithAngga menawarkan pendekatan pembelajaran yang mengajarkan tidak hanya sintaks, tetapi juga best practices dan design patterns untuk menjadi developer profesional. Ribuan developer Indonesia telah sukses melalui program kami dan kini bekerja di posisi prestisius dengan gaji kompetitif.

Selain itu, komunitas BuildWithAngga sangat aktif dan supportif. Kamu bisa join grup Discord atau WhatsApp untuk berdiskusi dengan teman-teman yang sedang belajar. Jangan ragu untuk bertanya, karena setiap developer pernah berada di posisi kamu dan tahu pentingnya mendapatkan bantuan saat stuck.

Langkah Pertama: Kuasai React Terlebih Dahulu

Jangan mencoba menguasai semua komponen MERN sekaligus. Fokus pada satu komponen sampai benar-benar menguasainya sebelum lanjut ke yang lain.

Rekomendasi: mulai dengan React. Alasannya: React paling visible dan interaktif, kamu akan melihat hasil langsung di browser. React memiliki dokumentasi excellent dan komunitas besar. Menguasai React memberikan pemahaman mendalam tentang state management, component lifecycle, dan hooks yang valuable untuk framework JavaScript lainnya.

Roadmap Pembelajaran React

Ikuti tahapan berikut:

Tahap 1: Pahami dasar React seperti JSX, komponen, props, dan state.

Tahap 2: Kuasai hooks, khususnya useState dan useEffect.

Tahap 3: Pelajari conditional rendering dan list rendering dengan map function.

Tahap 4: Kuasai handling forms dan events, validasi form.

Tahap 5: Pelajari API integration, hubungkan React dengan backend menggunakan fetch.

Setelah menyelesaikan semua tahap, kamu siap melanjutkan ke komponen MERN lainnya. Belajar Express, Node.js, dan MongoDB akan terasa lebih mudah karena kamu sudah memiliki fondasi kuat.

Buat Proyek Sendiri

Jangan hanya menonton tutorial. Mulai membuat proyek sendiri sejak awal pembelajaran. Mulai dengan proyek sederhana seperti todo list, weather app, atau simple e-commerce listing.

Membuat proyek sendiri mengajarkan debugging, error handling, organisasi kode, dan problem-solving skills. Portfolio berisi proyek yang kamu buat sendiri jauh lebih impressive bagi employer daripada sertifikat. Mereka ingin tahu bahwa kamu benar-benar bisa membuat aplikasi.

Ambil Keputusan Hari Ini

MERN Stack adalah pilihan tepat untuk memulai karier sebagai web developer modern. Investasi waktu kamu akan kembali berlipat ganda dalam bentuk karir cemerlang dan income kompetitif.

Mulai hari ini: bergabunglah dengan BuildWithAngga, fokus pada React terlebih dahulu, buat proyek sederhana, dan tetap konsisten. Dalam beberapa bulan, kamu akan menjadi developer yang capable dan siap untuk proyek-proyek kompleks.

Ribuan developer Indonesia sudah membuktikan MERN Stack adalah jalan yang tepat menuju sukses industri teknologi. Sekarang giliran kamu. Daftarkan diri kamu di BuildWithAngga dan mulai menulis kode React pertama kamu hari ini.