Jasa Setting Mikrotik

Membuat Aplikasi CRUD Api NodeJS React

Membuat Aplikasi CRUD Api NodeJS React - Pada tulisan Membuat Aplikasi CRUD Api NodeJS React saya mendokumentasikan percobaan-percobaan kecil terkait Cara Membuat Aplikasi CRUD Api NodeJS React, karena belakangan ini saya mulai tertarik dengan reactjs, nodejs, dan nextjs. 
Pertama sekali tentunya kita harus siapkan sebuah backend, untuk menjadi server apinya. Caranya mudah dalam membuat backend ini, yang terpenting anda harus sudah tahu cara menggunakan nodejs dan mengingstapp aplikasinya. 

Langkah pertama dalam membuat crud Api Mysql nodeJs dan React Membuat Aplikasi CRUD Api NodeJS React Install packagenya
npm init -y
npm install express mysql2 cors
Tunggu installasi sampai selesai, mungkin agak lama tergantung koneksi anda. 

Berikutnya buat file di root backend bernama db.js yang isinya begini:
import mysql from "mysql2"
const db = mysql.createConnection({
    host: "localhost",
    user: "root",
    password: "",
    database: "school_db"
})

db.connect((err) => {
    if (err) {
        console.log("Gagal koneksi ke database", err)
    } else {
        console.log("Terhubung ke database")
    }
})

export default db
Kemudian buat file route didalam directory route di root backend
// ============================================================
// backend/routes/students.js
// ROUTER UNTUK CRUD DATA SISWA
// ============================================================

// Import modul utama express & koneksi database
import express from "express";
import db from "../db.js";

// Buat router instance untuk menangani endpoint /api/students
const router = express.Router();


// ============================================================
// GET /api/students — Ambil semua data siswa dari database
// ============================================================
// Proses:
// 1. Jalankan query SELECT untuk mengambil seluruh isi tabel "students"
// 2. Jika error, kirim status 500 dengan pesan error
// 3. Jika sukses, kirim hasil dalam format JSON
router.get("/", (req, res) => {
    db.query("SELECT * FROM students", (err, results) => {
        if (err) return res.status(500).json({ error: err });
        res.json(results); // hasil dikirim ke frontend
    });
});


// ============================================================
// POST /api/students — Tambah siswa baru
// ============================================================
// Proses:
// 1. Ambil data `name`, `nis`, dan `class` dari body request
// 2. Jalankan query INSERT untuk menambah data baru ke database
// 3. Ambil kembali data yang baru disimpan (dengan SELECT by ID)
// 4. Kembalikan data baru ke frontend sebagai response
router.post("/", (req, res) => {
    const { name, nis, class: className } = req.body;
    const sql = "INSERT INTO students (name, nis, class) VALUES (?, ?, ?)";

    db.query(sql, [name, nis, className], (err, result) => {
        if (err) return res.status(500).json({ error: err });

        // Dapatkan ID siswa baru yang ditambahkan
        const newId = result.insertId;

        // Ambil data lengkap siswa yang baru dimasukkan
        db.query("SELECT * FROM students WHERE id=?", [newId], (err, rows) => {
            if (err) return res.status(500).json({ error: err });
            res.json(rows[0]); // kirim kembali data baru
        });
    });
});


// ============================================================
// PUT /api/students/:id — Edit / Update data siswa
// ============================================================
// Proses:
// 1. Ambil parameter `id` dari URL dan data baru dari body request
// 2. Jalankan query UPDATE untuk memperbarui data siswa
// 3. Setelah berhasil, ambil data terbaru dari database
// 4. Kembalikan data terbaru ke frontend
router.put("/:id", (req, res) => {
    const { id } = req.params; // ambil ID dari URL
    const { name, nis, class: className } = req.body; // ambil data dari body

    const sql = "UPDATE students SET name=?, nis=?, class=? WHERE id=?";
    db.query(sql, [name, nis, className, id], (err) => {
        if (err) return res.status(500).json({ error: err });

        // Ambil kembali data siswa setelah diupdate
        db.query("SELECT * FROM students WHERE id=?", [id], (err, rows) => {
            if (err) return res.status(500).json({ error: err });
            res.json(rows[0]); // kirim hasil update ke frontend
        });
    });
});


// ============================================================
// DELETE /api/students/:id — Hapus data siswa
// ============================================================
// Proses:
// 1. Ambil parameter `id` dari URL
// 2. Jalankan query DELETE untuk menghapus baris sesuai ID
// 3. Jika sukses, kirim pesan konfirmasi JSON ke frontend
router.delete("/:id", (req, res) => {
    const { id } = req.params;
    const sql = "DELETE FROM students WHERE id=?";

    db.query(sql, [id], (err) => {
        if (err) return res.status(500).json({ error: err });
        res.json({ message: "Data berhasil dihapus" });
    });
});


// ============================================================
// Ekspor router agar bisa dipakai di file server utama (server.js)
// ============================================================
export default router;
Selanjutnya buat file index.js di root backend
// index.js
import express from "express";
import cors from "cors";
import studentsRoute from "./routes/students.js";

const app = express();

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

app.use("/api/students", studentsRoute);

const PORT = 5000;
app.listen(PORT, () => console.log(`Server berjalan di port ${PORT}`));

Sebelum menjalankan servernya buat sebuah database bernama school_db
CREATE DATABASE school_db;

USE school_db;

CREATE TABLE students (
  id INT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(100),
  nis VARCHAR(50),
  class VARCHAR(50)
);
Isi databasenya untuk dummy
INSERT INTO students (name, nis, class)
VALUES 
('Andi Pratama', '12345', 'XII-A'),
('Siti Nurhaliza', '12346', 'XI-B'),
('Budi Santoso', '12347', 'X-A');

Buat Page/StudentPages.jsx
import { useEffect, useState } from "react";
import StudentForm from "../components/StudentForm";
import StudentList from "../components/StudentList";
import {
    getStudents,
    addStudent,
    updateStudent,
    deleteStudent,
} from "../services/studentService"; // Semua fungsi API dipisahkan di file service
// agar komponen ini tetap bersih dan mudah dikelola

// =====================================================
// Komponen utama untuk halaman siswa
// =====================================================
export default function StudentsPage() {
    // STATE MANAGEMENT
    // -----------------------------------------------------
    // Menyimpan daftar siswa (hasil fetch dari backend)
    const [students, setStudents] = useState([]);
    // Menyimpan data siswa yang sedang diedit (jika ada)
    const [editingStudent, setEditingStudent] = useState(null);
    // Menyimpan teks pencarian dari input filter
    const [searchTerm, setSearchTerm] = useState("");

    // =====================================================
    // 1. Load data awal (GET dari backend)
    // -----------------------------------------------------
    // Saat halaman pertama kali dimuat, ambil semua data siswa
    useEffect(() => {
        loadStudents();
    }, []);

    // Fungsi async untuk memanggil API dan memperbarui state
    const loadStudents = async () => {
        const data = await getStudents(); // → arah: frontend → backend (GET /api/students)
        setStudents(data); // data dari backend disimpan ke state
    };

    // =====================================================
    // 2. Tambah siswa (POST ke backend)
    // -----------------------------------------------------
    // Dipanggil oleh StudentForm saat user klik tombol "Tambah"
    // Flow:
    // - StudentForm kirim data lewat props onAddStudent(newStudent)
    // - Masuk ke handleAddStudent → panggil addStudent() di service
    // - Hasil dari backend langsung ditambahkan ke state `students`
    const handleAddStudent = async (newStudent) => {
        const added = await addStudent(newStudent); // POST → /api/students
        // langsung update tampilan tanpa reload
        setStudents((prev) => [added, ...prev]);
    };

    // =====================================================
    // 3. Update siswa (PUT ke backend)
    // -----------------------------------------------------
    // Dipanggil oleh StudentForm saat user klik "Simpan Perubahan"
    // Flow:
    // - StudentForm kirim props onUpdateStudent(updatedStudent)
    // - Masuk ke handleUpdateStudent → panggil updateStudent() di service
    // - Hasil edit langsung mengganti data lama dalam state
    const handleUpdateStudent = async (student) => {
        const updated = await updateStudent(student); // PUT → /api/students/:id
        // replace data lama dengan yang baru
        setStudents((prev) =>
            prev.map((s) => (s.id === updated.id ? updated : s))
        );
        setEditingStudent(null); // keluar dari mode edit
    };

    // =====================================================
    // 4. Masuk ke mode edit
    // -----------------------------------------------------
    // Dipanggil oleh StudentList → StudentItem (saat klik tombol Edit)
    // Data siswa yang diklik dikirim ke StudentForm agar form menampilkan datanya
    const handleEdit = (student) => {
        setEditingStudent(student);
    };

    // =====================================================
    // 5. Hapus siswa (DELETE ke backend)
    // -----------------------------------------------------
    // Dipanggil dari tombol "Hapus" di StudentList
    // Flow:
    // - StudentList kirim props onDelete(id)
    // - handleDelete kirim DELETE request ke backend
    // - lalu update state tanpa reload halaman
    const handleDelete = async (id) => {
        await deleteStudent(id); // DELETE → /api/students/:id
        setStudents((prev) => prev.filter((s) => s.id !== id)); // hapus dari state
    };

    // =====================================================
    // 6. Filter (pencarian siswa)
    // -----------------------------------------------------
    // Menyaring siswa berdasarkan nama yang diketik di input pencarian
    const filteredStudents = students.filter((s) =>
        s.name.toLowerCase().includes(searchTerm.toLowerCase())
    );

    // =====================================================
    // 7. Render UI
    // -----------------------------------------------------
    return (
        <div style={{ maxWidth: 900, margin: "0 auto", padding: 16 }}>
            <h1>Aplikasi Data Siswa</h1>

            {/* Input Pencarian */}
            <input
                type="text"
                placeholder="Cari nama siswa..."
                value={searchTerm}
                onChange={(e) => setSearchTerm(e.target.value)} // update searchTerm setiap ketikan
                style={{
                    width: "100%",
                    padding: "8px",
                    marginBottom: "16px",
                    borderRadius: "6px",
                    border: "1px solid #ccc",
                }}
            />

            {/* Komponen Form (Tambah/Edit Siswa)
                Props dikirim agar form tahu kapan mode edit/tambah
                dan bisa memanggil fungsi dari sini (callback) */}
            <StudentForm
                onAddStudent={handleAddStudent}         // untuk tambah
                onUpdateStudent={handleUpdateStudent}   // untuk simpan hasil edit
                editingStudent={editingStudent}         // data siswa yang sedang diedit
            />

            {/* Komponen Daftar Siswa
                Props:
                - students → daftar hasil filter pencarian
                - onDelete → fungsi hapus siswa
                - onEdit → fungsi masuk mode edit */}
            <StudentList
                students={filteredStudents}
                onDelete={handleDelete}
                onEdit={handleEdit}
            />
        </div>
    );
}
Buat folder components berisi file StudentList.jsx yang berisi code ini
export default function StudentList({ students, onDelete, onEdit }) {
    if (students.length === 0) return <p>Belum ada data siswa.</p>;

    return (
        <table width="100%" border="1" cellPadding="8">
            <thead>
                <tr>
                    <th>Nama</th>
                    <th>NIS</th>
                    <th>Kelas</th>
                    <th>Aksi</th>
                </tr>
            </thead>
            <tbody>
                {students.map((s) => (
                    <tr key={s.id}>
                        <td>{s.name}</td>
                        <td>{s.nis}</td>
                        <td>{s.class}</td>
                        <td>
                            <button onClick={() => onEdit(s)}>Edit</button>{" "}
                            <button onClick={() => onDelete(s.id)}>Hapus</button>
                        </td>
                    </tr>
                ))}
            </tbody>
        </table>
    );
}

didalam components buat juga file StudentItem.jsx berisini code ini
// ===========================================================
// 🔹 Komponen StudentItem
// -----------------------------------------------------------
// Bertugas menampilkan satu baris data siswa di dalam tabel.
// Menerima props dari StudentList untuk menampilkan data,
// serta callback onEdit & onDelete agar bisa memanggil fungsi
// di komponen induk (StudentsPage).
// ===========================================================

export default function StudentItem({ index, student, onDelete, onEdit }) {
    return (
        <tr>
            {/* 🔸 Kolom nomor urut */}
            <td style={{ border: "1px solid #ddd", padding: 8 }}>{index}</td>

            {/* 🔸 Kolom nama siswa */}
            <td style={{ border: "1px solid #ddd", padding: 8 }}>
                {student.name}
            </td>

            {/* 🔸 Kolom NIS */}
            <td style={{ border: "1px solid #ddd", padding: 8 }}>
                {student.nis}
            </td>

            {/* 🔸 Kolom kelas */}
            <td style={{ border: "1px solid #ddd", padding: 8 }}>
                {student.class}
            </td>

            {/* 🔸 Kolom aksi (Edit & Hapus) */}
            <td style={{ border: "1px solid #ddd", padding: 8 }}>
                {/* Tombol edit: kirim data siswa ke onEdit */}
                <button
                    style={{ marginRight: 6, backgroundColor: "#4caf50", color: "white", border: "none", padding: "6px 10px", borderRadius: "4px" }}
                    onClick={() => onEdit(student)}
                >
                    Edit
                </button>

                {/* Tombol hapus: kirim id siswa ke onDelete */}
                <button
                    style={{ backgroundColor: "#f44336", color: "white", border: "none", padding: "6px 10px", borderRadius: "4px" }}
                    onClick={() => onDelete(student.id)}
                >
                    Hapus
                </button>
            </td>
        </tr>
    );
}
Buat juga file StudentForm.jsx di folder components berisi code ini
  // ===========================================================
// 🔹 Komponen StudentForm
// -----------------------------------------------------------
// Bertanggung jawab untuk:
//  - Menangani input data siswa (nama, NIS, kelas)
//  - Menangani mode tambah dan mode edit
//  - Mengirim data ke parent (StudentsPage) lewat callback:
//       → onAddStudent()  → untuk data baru
//       → onUpdateStudent() → untuk update data
// ===========================================================

import { useEffect, useState } from "react";

export default function StudentForm({
    onAddStudent,      // Callback dari parent untuk menambah siswa baru
    onUpdateStudent,   // Callback dari parent untuk mengupdate data siswa
    editingStudent,    // Objek siswa yang sedang diedit (null jika mode tambah)
}) {
    // State untuk menyimpan isi form
    const [form, setForm] = useState({ name: "", nis: "", class: "" });

    // Efek samping: isi form otomatis ketika kita klik "Edit"
    useEffect(() => {
        if (editingStudent) {
            // Jika ada data yang sedang diedit → isi form dengan data tersebut
            setForm(editingStudent);
        } else {
            // Jika tidak ada yang sedang diedit → kosongkan form
            setForm({ name: "", nis: "", class: "" });
        }
    }, [editingStudent]); // depend on editingStudent agar bereaksi saat berubah

    // Handler ketika user mengetik di input
    const handleChange = (e) => {
        setForm({
            ...form,                    // salin semua data form lama
            [e.target.name]: e.target.value,  // ubah hanya field yang diketik
        });
    };

    // Handler ketika user menekan tombol submit
    const handleSubmit = (e) => {
        e.preventDefault(); // cegah reload halaman

        if (editingStudent) {
            // Jika sedang mode edit → kirim data ke parent lewat onUpdateStudent()
            onUpdateStudent(form);
        } else {
            // Jika mode tambah → kirim data baru lewat onAddStudent()
            onAddStudent(form);
        }

        // Setelah submit → kosongkan form agar siap input baru
        setForm({ name: "", nis: "", class: "" });
    };

    // ===========================================================
    // UI Bagian Form
    // ===========================================================
    return (
        <form
            onSubmit={handleSubmit}
            style={{
                marginBottom: 20,
                display: "flex",
                gap: 8,
                alignItems: "center",
            }}
        >
            <input
                name="name"
                placeholder="Nama"
                value={form.name}
                onChange={handleChange}
                required
                style={{ flex: 1, padding: 6 }}
            />
            <input
                name="nis"
                placeholder="NIS"
                value={form.nis}
                onChange={handleChange}
                required
                style={{ flex: 1, padding: 6 }}
            />
            <input
                name="class"
                placeholder="Kelas"
                value={form.class}
                onChange={handleChange}
                required
                style={{ flex: 1, padding: 6 }}
            />

            {/* Tombol berubah sesuai mode */}
            <button
                type="submit"
                style={{
                    padding: "8px 12px",
                    backgroundColor: editingStudent ? "#4caf50" : "#2196f3",
                    color: "white",
                    border: "none",
                    borderRadius: "6px",
                }}
            >
                {editingStudent ? "Update" : "Tambah"}
            </button>
        </form>
    );
}

Ubah File App.js isi dengan code ini
import StudentsPage from "./pages/StudentPages";

export default function App() {
  return <StudentsPage />;
}

Selesai sudah cara Membuat Aplikasi CRUD Api NodeJS React. Semoga bermanfaat.

Komentar