- Part 1: Backend — REST API Laravel
- Part 2: Setup React & Tampil Data
- Part 3: CRUD React ↔ API (sedang dibaca)
- Part 4: Pencarian & Autentikasi Sanctum
Di Part 2, React kita sudah bisa menampilkan data produk dari API Laravel. Sekarang di Part 3 kita buat aplikasi ini benar-benar interaktif dengan CRUD: menambah, mengedit, dan menghapus produk — semuanya langsung berkomunikasi dengan API Laravel.

Konsep CRUD di React
Kunci CRUD di React adalah state. Ketika kita menambah atau menghapus produk lewat API, kita juga memperbarui state produk di React. Karena React otomatis merender ulang saat state berubah, tampilan langsung ikut berubah tanpa perlu me-refresh halaman — inilah keunggulan aplikasi React.
Kita akan memakai instance axios (api) yang dibuat di Part 2, dengan base URL http://localhost:8000/api.
Membuat Form dengan Controlled Component
Di React, input form dikendalikan oleh state — disebut controlled component. Buat src/FormProduk.jsx:
import { useState } from 'react';
import api from './api';
function FormProduk({ onSimpan }) {
const [form, setForm] = useState({ nama: '', kategori: '', harga: '', stok: '' });
const handleChange = (e) => {
setForm({ ...form, [e.target.name]: e.target.value });
};
const handleSubmit = (e) => {
e.preventDefault();
api.post('/produk', form)
.then((res) => {
onSimpan(res.data.data);
setForm({ nama: '', kategori: '', harga: '', stok: '' });
})
.catch((err) => console.error('Gagal menyimpan:', err));
};
return (
<form onSubmit={handleSubmit}>
<input name="nama" value={form.nama} onChange={handleChange} placeholder="Nama produk" />
<input name="kategori" value={form.kategori} onChange={handleChange} placeholder="Kategori" />
<input name="harga" value={form.harga} onChange={handleChange} placeholder="Harga" type="number" />
<input name="stok" value={form.stok} onChange={handleChange} placeholder="Stok" type="number" />
<button type="submit">Simpan</button>
</form>
);
}
export default FormProduk;
Perhatikan pola handleChange: { ...form, [e.target.name]: e.target.value } menyalin seluruh nilai form lama, lalu menimpa satu field yang berubah. Berkat atribut name pada tiap input, satu fungsi bisa menangani semua field sekaligus.

Mengelola State di Komponen Induk
Agar form dan tabel saling terhubung, kita pindahkan state produk ke App.jsx sebagai induk. Ketika form menyimpan produk baru, ia memberi tahu induk lewat callback:
import { useState, useEffect } from 'react';
import api from './api';
import FormProduk from './FormProduk';
function App() {
const [produk, setProduk] = useState([]);
useEffect(() => {
api.get('/produk').then((res) => setProduk(res.data.data));
}, []);
// dipanggil saat produk baru ditambahkan
const tambahProduk = (baru) => {
setProduk([baru, ...produk]);
};
// hapus produk
const hapusProduk = (id) => {
if (!confirm('Yakin hapus produk ini?')) return;
api.delete(`/produk/${id}`)
.then(() => setProduk(produk.filter((p) => p.id !== id)))
.catch((err) => console.error(err));
};
return (
<div className="container">
<h1>Manajemen Produk</h1>
<FormProduk onSimpan={tambahProduk} />
<table border="1" cellPadding="8">
<thead>
<tr>
<th>Nama</th><th>Kategori</th><th>Harga</th><th>Stok</th><th>Aksi</th>
</tr>
</thead>
<tbody>
{produk.map((p) => (
<tr key={p.id}>
<td>{p.nama}</td>
<td>{p.kategori}</td>
<td>Rp {p.harga.toLocaleString('id-ID')}</td>
<td>{p.stok}</td>
<td>
<button onClick={() => hapusProduk(p.id)}>Hapus</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
export default App;
Cara Kerja Tambah dan Hapus
- Tambah: form mengirim
api.post('/produk', form). Setelah API merespons dengan data produk baru, callbacktambahProdukmenambahkannya ke depan array state — tabel langsung memperlihatkannya. - Hapus:
api.delete(...)mengirim permintaan ke API, lalusetProduk(produk.filter(...))membuang produk itu dari state — baris langsung hilang dari tabel tanpa reload.

Menambahkan Fitur Edit
Untuk edit, kita simpan produk yang sedang diedit di state, lalu kirim PUT. Berikut inti logikanya (bisa Anda kembangkan ke dalam form terpisah):
const [sedangEdit, setSedangEdit] = useState(null);
const updateProduk = (id, data) => {
api.put(`/produk/${id}`, data)
.then((res) => {
setProduk(produk.map((p) => (p.id === id ? res.data.data : p)));
setSedangEdit(null);
})
.catch((err) => console.error(err));
};
Pola produk.map((p) => (p.id === id ? dataBaru : p)) menggantikan satu produk yang diubah, sambil mempertahankan yang lain — cara umum memperbarui satu item dalam array state React.
Menampilkan Notifikasi Sederhana
Anda bisa menambahkan state pesan untuk memberi tahu pengguna:
const [pesan, setPesan] = useState('');
// setelah berhasil menyimpan
setPesan('Produk berhasil ditambahkan.');
setTimeout(() => setPesan(''), 3000);
Lalu tampilkan {pesan && <div className="alert">{pesan}</div>} di atas form. Notifikasi akan hilang otomatis setelah 3 detik.
Penutup
Aplikasi produk Anda kini benar-benar fullstack dan interaktif — React mengirim perubahan ke API Laravel, dan tampilan diperbarui secara instan lewat state, tanpa reload halaman. Anda telah menguasai inti CRUD di React: controlled component, mengirim data dengan axios, dan mengelola state array.
Di Part 4 pamungkas, kita tambahkan pencarian, filter, serta autentikasi dengan Laravel Sanctum agar API hanya bisa diakses pengguna yang login. Sampai jumpa!
Referensi: untuk pendalaman lebih lanjut, kunjungi dokumentasi resmi React dan Laravel.

