Tugas CRUD Tabel Mahasiswa dengan Modal (React + React-Bootstrap)
Persiapan Proyek
1. Buat project baru
npx create-react-app react-crud-modal
cd react-crud-modal
npm install react-bootstrap bootstrap axios2. Tambahkan Bootstrap ke project
Edit src/index.js:
import 'bootstrap/dist/css/bootstrap.min.css';3. Struktur folder
src/
├── api.js
├── components/
│ ├── StudentTable.js
│ ├── StudentModal.js
│ └── DeleteModal.js
└── App.js4. Konfigurasi API (src/api.js)
import axios from 'axios';
const api = axios.create({
baseURL: 'http://localhost:5000/api/students' // sesuaikan dengan backend kamu
});
export default api;5. Komponen: StudentTable.js
Menampilkan daftar mahasiswa dan tombol aksi.
import React, { useEffect, useState } from 'react';
import { Table, Button } from 'react-bootstrap';
import api from '../api';
function StudentTable({ onEdit, onDelete, onCreate }) {
const [students, setStudents] = useState([]);
const fetchStudents = async () => {
try {
const res = await api.get('/');
setStudents(res.data);
} catch (err) {
console.error('Gagal memuat data:', err);
}
};
useEffect(() => {
fetchStudents();
}, []);
return (
<div>
<div className="d-flex justify-content-between align-items-center mb-3">
<h4>Daftar Mahasiswa</h4>
<Button variant="primary" onClick={onCreate}>Tambah</Button>
</div>
<Table striped bordered hover>
<thead>
<tr>
<th>#</th>
<th>Nama</th>
<th>Jurusan</th>
<th>Usia</th>
<th>Aksi</th>
</tr>
</thead>
<tbody>
{students.map((s, idx) => (
<tr key={s.id}>
<td>{idx + 1}</td>
<td>{s.name}</td>
<td>{s.major}</td>
<td>{s.age}</td>
<td>
<Button
variant="warning"
size="sm"
className="me-2"
onClick={() => onEdit(s)}
>
Edit
</Button>
<Button
variant="danger"
size="sm"
onClick={() => onDelete(s)}
>
Hapus
</Button>
</td>
</tr>
))}
</tbody>
</Table>
</div>
);
}
export default StudentTable;6. Komponen: StudentModal.js
Modal untuk tambah & edit data mahasiswa.
import React, { useState, useEffect } from 'react';
import { Modal, Button, Form } from 'react-bootstrap';
import api from '../api';
function StudentModal({ show, handleClose, refresh, selected }) {
const [form, setForm] = useState({ name: '', major: '', age: '' });
useEffect(() => {
if (selected) setForm(selected);
else setForm({ name: '', major: '', age: '' });
}, [selected]);
const handleChange = (e) => {
setForm({ ...form, [e.target.name]: e.target.value });
};
const handleSubmit = async (e) => {
e.preventDefault();
try {
if (form.id) {
await api.put(`/${form.id}`, form);
} else {
await api.post('/', form);
}
refresh();
handleClose();
} catch (err) {
console.error('Gagal menyimpan data:', err);
}
};
return (
<Modal show={show} onHide={handleClose} centered>
<Modal.Header closeButton>
<Modal.Title>{form.id ? 'Edit Mahasiswa' : 'Tambah Mahasiswa'}</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form onSubmit={handleSubmit}>
<Form.Group className="mb-3">
<Form.Label>Nama</Form.Label>
<Form.Control
name="name"
value={form.name}
onChange={handleChange}
required
/>
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Jurusan</Form.Label>
<Form.Control
name="major"
value={form.major}
onChange={handleChange}
required
/>
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Usia</Form.Label>
<Form.Control
type="number"
name="age"
value={form.age}
onChange={handleChange}
required
/>
</Form.Group>
<div className="text-end">
<Button variant="secondary" onClick={handleClose} className="me-2">
Batal
</Button>
<Button variant="primary" type="submit">
Simpan
</Button>
</div>
</Form>
</Modal.Body>
</Modal>
);
}
export default StudentModal;7. Komponen: DeleteModal.js
Modal konfirmasi untuk menghapus data.
import React from 'react';
import { Modal, Button } from 'react-bootstrap';
import api from '../api';
function DeleteModal({ show, handleClose, refresh, selected }) {
const handleDelete = async () => {
try {
await api.delete(`/${selected.id}`);
refresh();
handleClose();
} catch (err) {
console.error('Gagal menghapus data:', err);
}
};
return (
<Modal show={show} onHide={handleClose} centered>
<Modal.Header closeButton>
<Modal.Title>Konfirmasi Hapus</Modal.Title>
</Modal.Header>
<Modal.Body>
<p>
Apakah kamu yakin ingin menghapus mahasiswa <strong>{selected?.name}</strong>?
</p>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
Batal
</Button>
<Button variant="danger" onClick={handleDelete}>
Hapus
</Button>
</Modal.Footer>
</Modal>
);
}
export default DeleteModal;8. File Utama: App.js
import React, { useState } from 'react';
import { Container } from 'react-bootstrap';
import StudentTable from './components/StudentTable';
import StudentModal from './components/StudentModal';
import DeleteModal from './components/DeleteModal';
function App() {
const [showForm, setShowForm] = useState(false);
const [showDelete, setShowDelete] = useState(false);
const [selected, setSelected] = useState(null);
const [refreshFlag, setRefreshFlag] = useState(false);
const refresh = () => setRefreshFlag(!refreshFlag);
const handleCreate = () => {
setSelected(null);
setShowForm(true);
};
const handleEdit = (student) => {
setSelected(student);
setShowForm(true);
};
const handleDelete = (student) => {
setSelected(student);
setShowDelete(true);
};
return (
<Container className="py-4">
<h1 className="mb-4 text-center">CRUD Mahasiswa (Modal Version)</h1>
<StudentTable
key={refreshFlag}
onCreate={handleCreate}
onEdit={handleEdit}
onDelete={handleDelete}
/>
<StudentModal
show={showForm}
handleClose={() => setShowForm(false)}
refresh={refresh}
selected={selected}
/>
<DeleteModal
show={showDelete}
handleClose={() => setShowDelete(false)}
refresh={refresh}
selected={selected}
/>
</Container>
);
}
export default App;9. Kriteria Penilaian
Aspek
Deskripsi
CRUD Berfungsi
Tambah, Edit, dan Hapus berjalan normal
Modal Interaktif
Semua aksi menggunakan modal, tidak halaman baru
Integrasi API
Data tersinkron dengan backend
React-Bootstrap
Menggunakan komponen Table, Modal, Form, Button
Desain Rapi
Layout bersih dan mudah digunakan
Kerapian Kode
Struktur file dan naming convention sesuai standar
Last updated