Bangun Aplikasi Flashcard Belajar dengan Next.js dan MongoDB

Bangun Aplikasi Flashcard Belajar dengan Next.js dan MongoDB

Bangun Aplikasi Flashcard Belajar dengan Next.js dan MongoDB

Pernah nggak belajar sambil ngerjain tugas atau ujian semalaman? Susah banget inget semua materi, kan? Flashcard jadi salah satu alat belajar paling efektif karena pakai **active recall** — otak dipaksa ambil informasi dari memori, bukan cuma baca ulang pelan-pelan.

Bikin aplikasi flashcard digital itu gabungan pengembangan web modern sama psikologi pendidikan. Di panduan ini, aku bakal ajak kalian bikin aplikasi flashcard full-stack pakai **Next.js** buat frontend/backend dan **MongoDB** buat nyimpen data.

---

Kenapa Harus Bikin Aplikasi Flashcard?

Flashcard digital punya keunggulan dibanding yang fisik:

- **Portabilitas**: Akses deck mana aja selama ada internet
- **Spaced repetition**: Algoritma bisa atur jadwal review optimal
- **Dukungan media**: Gambar, audio, formatting — bebas
- **Pelacakan progress**: Analytics performa belajar kita

Kasus Nyata

Sebelum ke kode, bayangin skenario ini:

1. **Mahasiswa Kedokteran**: Bikin flashcard anatomi detail pakai gambar
2. **Pelajar Bahasa**: Susun deck kosakata dengan audio pengucapan
3. **Sertifikasi Profesional**: Rapihin konsep teknis kompleks secara sistematis

---

Ringkasan Tech Stack

Kita pakai:

- **Next.js 14** (React framework dengan server-side rendering)
- **MongoDB Atlas** (database cloud)
- **Mongoose** (object modeling MongoDB)
- **Tailwind CSS** (styling)

Kenapa stack ini? Next.js urus frontend dan API routes sekaligus — deploy jadi lebih simpel. Skema MongoDB yang fleksibel cocok banget buat struktur flashcard yang beda-beda.

---

Setup Project

Pertama, bikin project Next.js baru:

```bash
npx create-next-app@latest flashcard-app
cd flashcard-app
npm install mongoose mongodb
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
```

Konfigurasi Tailwind di `tailwind.config.js`:

```javascript
/** @type {import('tailwindcss').tailwind.config} */
module.exports = {
content: [
"./app/**/*.{js,jsx,ts,jsx}",
"./pages/**/*.{js,jsx,ts,jsx}",
"./components/**/*.{js,jsx,ts,jsx}",
],
theme: {
extend: {},
},
plugins: [],
}
```

Tambahin ke `app/globals.css`:

```css
@tailwind base;
@tailwind components;
@tailwind utilities;
```

---

Koneksi Database

Bikin `lib/mongodb.js`:

```javascript
import { MongoClient } from 'mongodb'

const uri = process.env.MONGODB_URI
const options = {
useNewUrlParser: true,
useUnifiedTopology: true,
}

let client
let clientPromise

if (!process.env.MONGODB_URI) {
throw new Error('Please add your MongoDB URI to .env.local')
}

if (process.env.NODE_ENV === 'development') {
if (!global._mongoClientPromise) {
client = new MongoClient(uri, options)
global._mongoClientPromise = client.connect()
}
clientPromise = global._mongoClientPromise
} else {
client = new MongoClient(uri, options)
clientPromise = client.connect()
}

export default clientPromise
```

---

Model Flashcard

Di `models/Flashcard.js`:

```javascript
import mongoose from 'mongoose'

const flashcardSchema = new mongoose.Schema({
question: {
type: String,
required: true,
},
answer: {
type: String,
required: true,
},
deck: {
type: String,
required: true,
},
tags: [String],
createdAt: {
type: Date,
default: Date.now,
},
})

export default mongoose.models.Flashcard || mongoose.model('Flashcard', flashcardSchema)
```

---

API Routes

API routes Next.js handle logic backend. Bikin `pages/api/flashcards/index.js`:

```javascript
import dbConnect from '../../../lib/dbConnect'
import Flashcard from '../../../models/Flashcard'

export default async function handler(req, res) {
const { method } = req

await dbConnect()

switch (method) {
case 'GET':
try {
const flashcards = await Flashcard.find({})
res.status(200).json(flashcards)
} catch (error) {
res.status(400).json({ success: false })
}
break
case 'POST':
try {
const flashcard = await Flashcard.create(req.body)
res.status(201).json(flashcard)
} catch (error) {
res.status(400).json({ success: false })
}
break
default:
res.status(400).json({ success: false })
break
}
}
```

---

Komponen Frontend

Bikin form component `components/FlashcardForm.js`:

```javascript
import { useState } from 'react'

export default function FlashcardForm({ onSubmit }) {
const [question, setQuestion] = useState('')
const [answer, setAnswer] = useState('')
const [deck, setDeck] = useState('')

const handleSubmit = async (e) => {
e.preventDefault()
const response = await fetch('/api/flashcards', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ question, answer, deck })
})

if (response.ok) {
const newFlashcard = await response.json()
onSubmit(newFlashcard)
setQuestion('')
setAnswer('')
setDeck('')
}
}

return (



value={question}
onChange={(e) => setQuestion(e.target.value)}
required
className="w-full p-2 border rounded"
/>



value={answer}
onChange={(e) => setAnswer(e.target.value)}
required
className="w-full p-2 border rounded"
/>



type="text"
value={deck}
onChange={(e) => setDeck(e.target.value)}
required
className="w-full p-2 border rounded"
/>



)
}
```

---

Interface Mode Belajar

Bikin `components/StudyMode.js` buat latihan active recall:

```javascript
import { useState, useEffect } from 'react'

export default function StudyMode({ flashcards }) {
const [currentIndex, setCurrentIndex] = useState(0)
const [showAnswer, setShowAnswer] = useState(false)
const [shuffledCards, setShuffledCards] = useState([])

useEffect(() => {
setShuffledCards([...flashcards].sort(() => Math.random() - 0.5))
}, [flashcards])

const nextCard = () => {
setShowAnswer(false)
if (currentIndex < shuffledCards.length - 1) {
setCurrentIndex(currentIndex + 1)
}
}

const prevCard = () => {
setShowAnswer(false)
if (currentIndex > 0) {
setCurrentIndex(currentIndex - 1)
}
}

if (!shuffledCards.length) return

Tidak ada flashcard tersedia



const card = shuffledCards[currentIndex]

return (


Pertanyaan:


{card.question}




{showAnswer && (

Jawaban:


{card.answer}



)}





{currentIndex > 0 && (

)}
{currentIndex < shuffledCards.length - 1 && (

)}




Kartu {currentIndex + 1} dari {shuffledCards.length}



)
}
```

---

Halaman Utama Aplikasi

Bikin `app/page.js`:

```javascript
import { useState, useEffect } from 'react'
import FlashcardForm from '../components/FlashcardForm'
import StudyMode from '../components/StudyMode'

export default function Home() {
const [flashcards, setFlashcards] = useState([])
const [activeView, setActiveView] = useState('create')
const [selectedDeck, setSelectedDeck] = useState('')

useEffect(() => {
fetchFlashcards()
}, [])

const fetchFlashcards = async () => {
const response = await fetch('/api/flashcards')
const data = await response.json()
setFlashcards(data)
}

const addFlashcard = (newFlashcard) => {
setFlashcards([newFlashcard, ...flashcards])
}

const filteredCards = selectedDeck
? flashcards.filter(card => card.deck === selectedDeck)
: flashcards

const decks = [...new Set(flashcards.map(card => card.deck))]

return (


Aplikasi Flashcard Belajar




onClick={() => setActiveView('create')}
className={`px-4 py-2 mr-2 rounded ${
activeView === 'create' ? 'bg-blue-500 text-white' : 'bg-white'
}`}
>
Buat Flashcard

onClick={() => setActiveView('study')}
className={`px-4 py-2 rounded ${
activeView === 'study' ? 'bg-blue-500 text-white' : 'bg-white'
}`}
disabled={flashcards.length === 0}
>
Mode Belajar



{activeView === 'create' && (



)}

{activeView === 'study' && (


value={selectedDeck}
onChange={(e) => setSelectedDeck(e.target.value)}
className="w-full p-2 border rounded"
>

{decks.map(deck => (

))}


)}

{activeView === 'study' && }


Deck Kamu


{decks.length === 0 ? (

Belum ada deck. Buat flashcard pertama di atas!


) : (

    {decks.map(deck => (

  • {deck} ({flashcards.filter(c => c.deck === deck).length} kartu)

  • ))}

)}



)
}
```

---

Pertimbangan Deployment

Buat production, pertimbangkan enhancement ini:

1. **Autentikasi**: Tambah akun user pakai NextAuth.js
2. **Spaced Repetition**: Implementasikan algoritma kayak SM-2
3. **Rich Media**: Dukung gambar dan audio di flashcard
4. **Offline Support**: Pakai service worker buat kemampuan PWA

Deploy ke Vercel (dioptimasiin buat Next.js) atau platform serupa. Setup cluster MongoDB Atlas dan konfigurasi environment variables.

---

Penutup

Aplikasi flashcard ini demonstrasiin konsep inti sambil tetap praktis. Sekarang kalian punya fondasi yang bisa dikembangkan sesuai kebutuhan. Mau belajar bahasa, persiapan ujian, atau hafal materi profesional — flashcard digital memberikan solusi efektif dan bisa dikustomisasi.

Mulai dari yang simpel, iterasi terus, dan fokus ke pengalaman user inti. Semoga sukses buat perjalanan belajar kalian!

---

FAQ

Q: Butuh pengalaman MongoDB dulu nggak?
A: Basic familiarity membantu tapi nggak wajib. Model dokumen MongoDB intuitif banget kalau udah paham struktur kayak JSON.

Q: Bisa tambah gambar ke flashcard nggak?
A: Bisa! Extend schema dengan URL gambar dan modifikasi komponen form buat handle upload file.

Q: Gimana implementasi spaced repetition?
A: Simpan history review dengan timestamp, terus hitung interval optimal berdasarkan performa recall. Library kayak `supermemo` bisa bantu algoritmanya.

Q: Cocok buat mobile nggak?
A: Dengan framework CSS responsive kayak Tailwind, iya. Pertimbangkan tambah fitur PWA buat pengalaman kayak native app.

Comments (0)

No comments yet. Be the first to comment!

Leave a Comment