1. Pengantar Kursus Full-Stack Developer
Kursus ini dirancang untuk membimbing Anda menjadi full-stack developer yang handal melalui 15 proyek praktis yang mencakup frontend, backend, database, dan deployment. Anda akan belajar teknologi modern seperti React, Node.js, Express, MongoDB, dan banyak lagi.
Setiap proyek dirancang untuk memberikan pengalaman nyata dalam membangun aplikasi web lengkap, mulai dari desain UI hingga API dan deployment.
3. Step by Step Pembelajaran
3.1 Membuat To-Do List dengan React dan Local Storage
Langkah pertama adalah membuat aplikasi To-Do List sederhana menggunakan React. Aplikasi ini menyimpan data ke local storage agar tetap tersimpan walau halaman direfresh.
import React, { useState, useEffect } from 'react';
function TodoApp() {
const [todos, setTodos] = useState(() => {
const saved = localStorage.getItem('todos');
return saved ? JSON.parse(saved) : [];
});
const [input, setInput] = useState('');
useEffect(() => {
localStorage.setItem('todos', JSON.stringify(todos));
}, [todos]);
const addTodo = () => {
if (input.trim() === '') return;
setTodos([...todos, { id: Date.now(), text: input, completed: false }]);
setInput('');
};
const toggleTodo = (id) => {
setTodos(
todos.map(todo => todo.id === id ? { ...todo, completed: !todo.completed } : todo)
);
};
return (
<div className="max-w-md mx-auto p-6 bg-white rounded shadow">
<h2 className="text-2xl font-bold mb-4 text-indigo-700">To-Do List</h2>
<div className="flex mb-4">
<input
type="text"
className="flex-grow border border-gray-300 rounded px-3 py-2 mr-2"
placeholder="Tambah tugas baru"
value={input}
onChange={e => setInput(e.target.value)}
onKeyDown={e => e.key === 'Enter' && addTodo()}
/>
<button
className="bg-indigo-600 text-white px-4 py-2 rounded hover:bg-indigo-700"
onClick={addTodo}
>Tambah</button>
</div>
<ul>
{todos.map(todo => (
<li
key={todo.id}
onClick={() => toggleTodo(todo.id)}
className={`cursor-pointer mb-2 ${todo.completed ? 'line-through text-gray-400' : ''}`}
>
{todo.text}
</li>
))}
</ul>
</div>
);
}
export default TodoApp;
3.2 Membuat RESTful API dengan Node.js dan Express
Selanjutnya, buat backend sederhana menggunakan Node.js dan Express untuk mengelola data To-Do List.
const express = require('express');
const cors = require('cors');
const app = express();
const port = 5000;
app.use(cors());
app.use(express.json());
let todos = [];
app.get('/todos', (req, res) => {
res.json(todos);
});
app.post('/todos', (req, res) => {
const todo = { id: Date.now(), text: req.body.text, completed: false };
todos.push(todo);
res.status(201).json(todo);
});
app.put('/todos/:id', (req, res) => {
const id = parseInt(req.params.id);
todos = todos.map(todo => todo.id === id ? { ...todo, completed: req.body.completed } : todo);
res.json({ message: 'Updated' });
});
app.listen(port, () => {
console.log(`Server berjalan di http://localhost:${port}`);
});
3.3 Menghubungkan Frontend dan Backend
Modifikasi aplikasi React untuk mengambil dan mengirim data ke backend Express.
import React, { useState, useEffect } from 'react';
function TodoApp() {
const [todos, setTodos] = useState([]);
const [input, setInput] = useState('');
useEffect(() => {
fetch('http://localhost:5000/todos')
.then(res => res.json())
.then(data => setTodos(data));
}, []);
const addTodo = () => {
if (input.trim() === '') return;
fetch('http://localhost:5000/todos', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text: input }),
})
.then(res => res.json())
.then(newTodo => {
setTodos([...todos, newTodo]);
setInput('');
});
};
const toggleTodo = (id, completed) => {
fetch(`http://localhost:5000/todos/${id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ completed: !completed }),
}).then(() => {
setTodos(
todos.map(todo => todo.id === id ? { ...todo, completed: !completed } : todo)
);
});
};
return (
<div className="max-w-md mx-auto p-6 bg-white rounded shadow">
<h2 className="text-2xl font-bold mb-4 text-indigo-700">To-Do List</h2>
<div className="flex mb-4">
<input
type="text"
className="flex-grow border border-gray-300 rounded px-3 py-2 mr-2"
placeholder="Tambah tugas baru"
value={input}
onChange={e => setInput(e.target.value)}
onKeyDown={e => e.key === 'Enter' && addTodo()}
/>
<button
className="bg-indigo-600 text-white px-4 py-2 rounded hover:bg-indigo-700"
onClick={addTodo}
>Tambah</button>
</div>
<ul>
{todos.map(todo => (
<li
key={todo.id}
onClick={() => toggleTodo(todo.id, todo.completed)}
className={`cursor-pointer mb-2 ${todo.completed ? 'line-through text-gray-400' : ''}`}
>
{todo.text}
</li>
))}
</ul>
</div>
);
}
export default TodoApp;
3.4 Deployment dengan Docker dan Heroku
Setelah aplikasi selesai, Anda dapat melakukan containerization dengan Docker dan deploy ke Heroku.
# Dockerfile untuk backend Express
FROM node:16-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 5000
CMD ["node", "index.js"]
# Perintah deploy ke Heroku
heroku create nama-aplikasi-anda
git push heroku main
heroku open
4. Source Code Contoh Proyek
Berikut adalah contoh source code lengkap untuk proyek To-Do List full-stack sederhana.
4.1 Frontend React (src/TodoApp.js)
import React, { useState, useEffect } from 'react';
function TodoApp() {
const [todos, setTodos] = useState([]);
const [input, setInput] = useState('');
useEffect(() => {
fetch('http://localhost:5000/todos')
.then(res => res.json())
.then(data => setTodos(data));
}, []);
const addTodo = () => {
if (input.trim() === '') return;
fetch('http://localhost:5000/todos', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text: input }),
})
.then(res => res.json())
.then(newTodo => {
setTodos([...todos, newTodo]);
setInput('');
});
};
const toggleTodo = (id, completed) => {
fetch(`http://localhost:5000/todos/${id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ completed: !completed }),
}).then(() => {
setTodos(
todos.map(todo => todo.id === id ? { ...todo, completed: !completed } : todo)
);
});
};
return (
<div className="max-w-md mx-auto p-6 bg-white rounded shadow">
<h2 className="text-2xl font-bold mb-4 text-indigo-700">To-Do List</h2>
<div className="flex mb-4">
<input
type="text"
className="flex-grow border border-gray-300 rounded px-3 py-2 mr-2"
placeholder="Tambah tugas baru"
value={input}
onChange={e => setInput(e.target.value)}
onKeyDown={e => e.key === 'Enter' && addTodo()}
/>
<button
className="bg-indigo-600 text-white px-4 py-2 rounded hover:bg-indigo-700"
onClick={addTodo}
>Tambah</button>
</div>
<ul>
{todos.map(todo => (
<li
key={todo.id}
onClick={() => toggleTodo(todo.id, todo.completed)}
className={`cursor-pointer mb-2 ${todo.completed ? 'line-through text-gray-400' : ''}`}
>
{todo.text}
</li>
))}
</ul>
</div>
);
}
export default TodoApp;
4.2 Backend Express (index.js)
const express = require('express');
const cors = require('cors');
const app = express();
const port = 5000;
app.use(cors());
app.use(express.json());
let todos = [];
app.get('/todos', (req, res) => {
res.json(todos);
});
app.post('/todos', (req, res) => {
const todo = { id: Date.now(), text: req.body.text, completed: false };
todos.push(todo);
res.status(201).json(todo);
});
app.put('/todos/:id', (req, res) => {
const id = parseInt(req.params.id);
todos = todos.map(todo => todo.id === id ? { ...todo, completed: req.body.completed } : todo);
res.json({ message: 'Updated' });
});
app.listen(port, () => {
console.log(`Server berjalan di http://localhost:${port}`);
});