Já passou a noite toda estudando para uma prova? Se sim, sabe bem como é difícil memorizar tanta coisa de uma só vez. Os flashcards são uma das ferramentas de estudo mais eficazes porque usam a técnica de reavaliação ativa — obrigam seu cérebro a buscar as informações em vez de só ler de passagem.
Desenvolver um aplicativo digital de flashcards junta o melhor do desenvolvimento web moderno com princípios da psicologia do aprendizado. Neste guia, vou te mostrar passo a passo como criar um aplicativo completo de flashcards usando Next.js no frontend e backend, e MongoDB para armazenar os dados.
Por que construir um aplicativo de flashcards?
Flashcards digitais têm vantagens significativas sobre os físicos:
- **Portabilidade**: Acesse seus decks de qualquer lugar com internet
- **Repetição espaçada**: Algoritmos podem otimizar os momentos de revisão
- **Suporte a mídia**: Imagens, áudios e formatação rica
- **Acompanhamento de progresso**: Análises detalhadas do seu desempenho
Casos de uso reais
Antes de mergulhar no código, pense nesses cenários em que nosso app brilha:
1. **Estudantes de Medicina**: Criando flashcards detalhados de anatomia com imagens
2. **Pessoas aprendendo idiomas**: Montando decks de vocabulário com áudio de pronúncia
3. **Certificações profissionais**: Organizando conceitos técnicos complexos de forma sistemática
Visão geral da stack
Vamos usar:
- **Next.js 14** (framework React com renderização no servidor)
- **MongoDB Atlas** (banco de dados em nuvem)
- **Mongoose** (modelagem de objetos para MongoDB)
- **Tailwind CSS** (estilização)
Por que essa stack? Next.js cuida tanto do frontend quanto das rotas de API, simplificando muito o deploy. O esquema flexível do MongoDB funciona muito bem com flashcards que podem ter estruturas diferentes.
Configurando o projeto
Primeiro, crie um novo projeto Next.js:
```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
```
Configure o Tailwind no arquivo `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: [],
}
```
Adicione ao arquivo `app/globals.css`:
```css
@tailwind base;
@tailwind components;
@tailwind utilities;
```
Conexão com o banco de dados
Crie o arquivo `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('Por favor, adicione sua URI do MongoDB ao .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
```
Criando o modelo de Flashcard
No arquivo `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)
```
Rotas da API
As rotas de API do Next.js lidam com nossa lógica backend. Crie `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
}
}
```
Componentes frontend
Crie o componente de formulário `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 (
)
}
```
Interface de estudo
Crie `components/StudyMode.js` para praticar com reavaliação ativa:
```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
Nenhum flashcard disponível
const card = shuffledCards[currentIndex]
return (
Pergunta:
{card.question}
{showAnswer && (
Resposta:
{card.answer}
)}
onClick={() => setShowAnswer(!showAnswer)}
className="bg-gray-500 text-white px-4 py-2 rounded"
>
{showAnswer ? 'Ocultar Resposta' : 'Mostrar Resposta'}
{currentIndex > 0 && (
)}
{currentIndex < shuffledCards.length - 1 && (
)}
Cartão {currentIndex + 1} de {shuffledCards.length}
)
}
```
Página principal do aplicativo
Crie `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 (
Aplicativo de Flashcards
onClick={() => setActiveView('create')}
className={`px-4 py-2 mr-2 rounded ${
activeView === 'create' ? 'bg-blue-500 text-white' : 'bg-white'
}`}
>
Criar Flashcards
onClick={() => setActiveView('study')}
className={`px-4 py-2 rounded ${
activeView === 'study' ? 'bg-blue-500 text-white' : 'bg-white'
}`}
disabled={flashcards.length === 0}
>
Modo de Estudo
{activeView === 'create' && (
)}
{activeView === 'study' && (
value={selectedDeck}
onChange={(e) => setSelectedDeck(e.target.value)}
className="w-full p-2 border rounded"
>
{decks.map(deck => (
))}
)}
{activeView === 'study' &&
Seus Decks
{decks.length === 0 ? (
Nenhum deck criado ainda. Crie seu primeiro flashcard acima!
) : (
{deck} ({flashcards.filter(c => c.deck === deck).length} cartões)
{decks.map(deck => (
))}
)}
)
}
```
Considerações para produção
Para ambiente de produção, pense nesses aprimoramentos:
1. **Autenticação**: Adicione contas de usuário com NextAuth.js
2. **Repetição espaçada**: Implemente algoritmos como SM-2
3. **Mídia rica**: Suporte imagens e áudios nos flashcards
4. **Funcionamento offline**: Use service workers para recursos PWA
Faça o deploy na Vercel (otimizada para Next.js) ou outra plataforma similar. Configure seu cluster no MongoDB Atlas e ajuste as variáveis de ambiente.
Conclusão
Este aplicativo de flashcards demonstra conceitos fundamentais enquanto permanece prático. Agora você tem uma base sólida que pode ser expandida conforme suas necessidades. Seja estudando idiomas, se preparando para provas ou memorizando conteúdo profissional, flashcards digitais oferecem uma solução eficaz e personalizável.
Comece simples, itere frequentemente e foque na experiência do usuário. Boa sorte na sua jornada de aprendizado!
Perguntas frequentes
P: Preciso ter experiência prévia com MongoDB?
R: Conhecimento básico ajuda, mas não é obrigatório. O modelo de documentos do MongoDB é bem intuitivo quando você entende estruturas tipo JSON.
P: Posso adicionar imagens aos flashcards?
R: Com certeza! Estenda o schema com URLs de imagens e modifique os componentes do formulário para lidar com uploads de arquivos.
P: Como implemento a repetição espaçada?
R: Armazene o histórico de revisões com timestamps, depois calcule intervalos ótimos baseados no desempenho de recomendação. Bibliotecas como `supermemo` podem te ajudar com os algoritmos.
P: Este app é adequado para dispositivos móveis?
R: Com frameworks CSS responsivos como Tailwind, sim. Considere adicionar recursos PWA para uma experiência mais próxima da nativa.
Comments (0)
No comments yet. Be the first to comment!
Leave a Comment