Halo teman-teman semuanya, pada tutorial sebelumnya, kita telah belajar bagaimana cara menambahkan data (insert) ke dalam database menggunakan REST API dengan React dan TypeScript. Kali ini, kita akan melanjutkan belajar dengan membuat fitur untuk mengedit dan memperbarui data yang sudah ada.
Langkah 1 - Edit dan Update Data di React
Silahkan teman-teman buat file baru dengan nama edit.tsx
di dalam folder src/views/products
, kemudian masukkan kode berikut ini di dalamnya.
src/views/products/edit.tsx
// import hook useState, useEffect and Interface ChangeEvent, FormEvent dari react
import { FC, useState, useEffect, ChangeEvent, FormEvent } from "react";
// import useNavigate dan useParams dari react-router
import { useNavigate, useParams } from "react-router";
// import api dari folder api
import Api from "../../api";
// Interface Errors
interface Errors {
image?: string[];
title?: string[];
description?: string[];
price?: string[];
stock?: string[];
}
const ProductEdit: FC = () => {
// init state untuk image, title, description, price dan stock
const [image, setImage] = useState<File | null>(null);
const [title, setTitle] = useState<string>("");
const [description, setDescription] = useState<string>("");
const [price, setPrice] = useState<string>("");
const [stock, setStock] = useState<string>("");
// State untuk error
const [errors, setErrors] = useState<Errors>({});
// init useNavigate
const navigate = useNavigate();
//destructuring id dari useParams
const { id } = useParams<{ id: string }>();
// Fetch detail product
const fetchDetailProduct = async () => {
try {
// Fetch data product by id
const response = await Api.get(`/api/products/${id}`);
// Set data product ke state
setTitle(response.data.data.title);
setDescription(response.data.data.description);
setPrice(response.data.data.price);
setStock(response.data.data.stock);
} catch (error: any) {
console.error("Error fetching product:", error);
}
};
// useEffect
useEffect(() => {
fetchDetailProduct();
}, []);
// Handle perubahan file
const handleFileChange = (e: ChangeEvent<HTMLInputElement>) => {
if (e.target.files && e.target.files[0]) {
setImage(e.target.files[0]);
}
};
// Handle submit form
const updateProduct = async (e: FormEvent) => {
e.preventDefault();
// Membuat FormData
const formData = new FormData();
if (image) formData.append("image", image);
formData.append("title", title);
formData.append("description", description);
formData.append("price", price);
formData.append("stock", stock);
formData.append("_method", "PUT");
try {
// Kirim data ke API
await Api.post(`/api/products/${id}`, formData);
// Redirect ke halaman products
navigate("/products");
} catch (error: any) {
// Set error
setErrors(error.response.data);
}
};
return (
<div className="container mt-5">
<div className="row">
<div className="col-md-12">
<div className="card border-0 rounded-3 shadow">
<div className="card-body">
<form onSubmit={updateProduct}>
<div className="mb-3">
<label className="form-label fw-bold">Image</label>
<input
type="file"
onChange={handleFileChange}
className="form-control"
/>
{errors.image && (
<div className="alert alert-danger mt-2">
{errors.image[0]}
</div>
)}
</div>
<div className="mb-3">
<label className="form-label fw-bold">Title</label>
<input
type="text"
className="form-control"
value={title}
onChange={(e) => setTitle(e.target.value)}
placeholder="Title Product"
/>
{errors.title && (
<div className="alert alert-danger mt-2">
{errors.title[0]}
</div>
)}
</div>
<div className="mb-3">
<label className="form-label fw-bold">Description</label>
<textarea
className="form-control"
value={description}
onChange={(e) => setDescription(e.target.value)}
rows={5}
placeholder="Description Product"
/>
{errors.description && (
<div className="alert alert-danger mt-2">
{errors.description[0]}
</div>
)}
</div>
<div className="row">
<div className="col-md-6">
<div className="mb-3">
<label className="form-label fw-bold">Price</label>
<input
type="number"
className="form-control"
value={price}
onChange={(e) => setPrice(e.target.value)}
placeholder="Price Product"
/>
</div>
{errors.price && (
<div className="alert alert-danger mt-2">
{errors.price[0]}
</div>
)}
</div>
<div className="col-md-6">
<div className="mb-3">
<label className="form-label fw-bold">Stock</label>
<input
type="number"
className="form-control"
value={stock}
onChange={(e) => setStock(e.target.value)}
placeholder="Stock Product"
/>
</div>
{errors.stock && (
<div className="alert alert-danger mt-2">
{errors.stock[0]}
</div>
)}
</div>
</div>
<button
type="submit"
className="btn btn-md btn-primary rounded-5 shadow border-0"
>
Save
</button>
</form>
</div>
</div>
</div>
</div>
</div>
);
};
export default ProductEdit;
Dari penambahan kode di atas, pertama kita import Type FC
, hook useState
dan useEffect
, Interface changeEvent
dan FormEvent
dari React.
// import hook useState, useEffect and Interface ChangeEvent, FormEvent dari react
import { FC, useState, useEffect, ChangeEvent, FormEvent } from "react";
Kemudian kita import hook useNavigate
dan useParams
dari React Router.
// import useNavigate dan useParams dari react-router
import { useNavigate, useParams } from "react-router";
Selanjutnya, kita import service API.
// import api dari folder api
import Api from "../../api";
Dan kita membuat interface dengan nama Errors
.
// Interface Errors
interface Errors {
image?: string[];
title?: string[];
description?: string[];
price?: string[];
stock?: string[];
}
Di dalam function component ProductEdit
, kita membuat beberapa state.
// init state untuk image, title, description, price dan stock
const [image, setImage] = useState<File | null>(null);
const [title, setTitle] = useState<string>("");
const [description, setDescription] = useState<string>("");
const [price, setPrice] = useState<string>("");
const [stock, setStock] = useState<string>("");
// State untuk error
const [errors, setErrors] = useState<Errors>({});
Selanjutnya, kita inisialisasi navigate
.
// init useNavigate
const navigate = useNavigate();
Kemudian kita melakukan desctruct id
dari hook useParams
.
//destructuring id dari useParams
const { id } = useParams<{ id: string }>();
Setelah itu, kita buat function baru dengan nama fetchDetailPost
.
//method fetchDetailPost
const fetchDetailPost = async () => {
//...
}
Di dalamnya kita melakukan fetching ke Rest API berdasarkan parameter id
yang didapatkan dari URL.
// Fetch data product by id
const response = await Api.get(`/api/products/${id}`);
Jika data ditemukan, maka kita akan assign response data-nya ke dalam state.
// Set data product ke state
setTitle(response.data.data.title);
setDescription(response.data.data.description);
setPrice(response.data.data.price);
setStock(response.data.data.stock);
Agar function fetchDetailPost
bisa jalankan saat halaman diakses, maka kita perlu memanggilnya di dalam hook useEffect
.
// useEffect
useEffect(() => {
fetchDetailProduct();
}, []);
Kita buat function lagi untuk menghandle file yang akan diupload.
// Handle perubahan file
const handleFileChange = (e: ChangeEvent<HTMLInputElement>) => {
if (e.target.files && e.target.files[0]) {
setImage(e.target.files[0]);
}
};
Terakhir, kita buat function yang bernama updateProduct
. Function ini akan dijalakan ketika form disumbit.
<form onSubmit={updateProduct}>
//...
</form>
// Handle submit form
const updateProduct = async (e: FormEvent) => {
//...
}
Di dalam function di atas, sama seperti yang ada pada function storePost
pada pembahasan artikel sebelumnya, bedanya disini kita tambahkan sebuah key _method
dengan value PUT
pada append
. Karena data yang dikirimkan adalah proses update data.
// Membuat FormData
const formData = new FormData();
if (image) formData.append("image", image);
formData.append("title", title);
formData.append("description", description);
formData.append("price", price);
formData.append("stock", stock);
formData.append("_method", "PUT");
Setelah itu, kita tinggal kirimkan data-nya melalui Axios
dengan method POST
.
// Kirim data ke API
await Api.post(`/api/products/${id}`, formData);
Jika proses update data berhasil dilakukan, maka kita redirect atau arahkan pada halaman products index.
// Redirect ke halaman products
navigate("/products");
Jika data gagal diupdate, maka kita assign error response validasinya ke dalam state errors
.
// Set error
setErrors(error.response.data);
Jangan lupa pada input di dalam form kita berikan value
yang berisi state title
, description
, price
dan stock
. Ini bertujuan agar menampilkan data yang akan diedit.
<input
type="text"
className="form-control"
value={title} // tambahkan ini
onChange={(e) => setTitle(e.target.value)}
placeholder="Title Product"
/>
Langkah 2 - Konfigurasi Route Products Edit
Silahkan teman-teman buka file src/routes/index.tsx
, kemudian ubah kode-nya menjadi seperti berikut ini.
src/routes/index.tsx
// Import FC from React
import { FC } from "react";
// Import React Router
import { Routes, Route } from "react-router";
// Import view HomePage
import Home from "../views/home";
// Import view ProductIndex
import ProductIndex from "../views/products/index";
// Import view ProductCreate
import ProductCreate from "../views/products/create";
// Import view ProductEdit
import ProductEdit from "../views/products/edit";
// Definisikan component dengan Type FC (Functional Component)
const RoutesIndex: FC = () => {
return (
<Routes>
{/* Route untuk halaman utama */}
<Route path="/" element={<Home />} />
{/* Route untuk halaman products */}
<Route path="/products" element={<ProductIndex />} />
{/* Route untuk halaman create product */}
<Route path="/products/create" element={<ProductCreate />} />
{/* Route untuk halaman edit product */}
<Route path="/products/edit/:id" element={<ProductEdit />} />
</Routes>
);
};
export default RoutesIndex;
Dari perubahan kode di atas, kita import view products edit.
// Import view ProductEdit
import ProductEdit from "../views/products/edit";
Kemudian kita buat konfigurasi route-nya dengan path /products/edit/:id
.
{/* Route untuk halaman edit product */}
<Route path="/products/edit/:id" element={<ProductEdit />} />
Langkah 3 - Uji Coba Edit dan Update Data
Silahkan teman-teman klik button EDIT
yang ada pada data yang dimiliki, jika berhasil maka akan menampilkan halaman form edit data seperti berikut.

Silahkan sesuaikan isinya, kemudian klik button Update
. Jika berhasil maka kita akan diarahkan ke halaman products index dengan data yang telah diperbarui.

Kesimpulan
Pada artikel ini, kita telah belajar bagaimana cara menampilkan detail data product yang akan diedit pada sebuah form, kemudian melakukan proses update.
Pada artikel selanjutnya, kita semua akan belajar bagaimana cara membuat fitur proses delete data product dengan Rest API di React TypeScript.
Terima Kasih