Halo teman-teman semuanya, pada tutorial sebelumnya, kita telah belajar bagaimana cara menampilkan data dari REST API menggunakan React dan TypeScript. Kali ini, kita akan melanjutkan belajar dengan membuat fitur untuk menambahkan data (Insert Data) ke dalam database menggunakan API.
Dalam tutorial ini, kita akan menggunakan Axios untuk mengirim data ke backend yang dibuat dengan Laravel. Tidak hanya itu, kita juga akan menambahkan fitur upload gambar, sehingga pengguna dapat mengunggah gambar product langsung dari aplikasi React.
Langkah 1 - Insert dan Upload Data di React
Silahkan teman-teman buat file baru dengan nama create.tsx
di dalam folder src/views/products
, kemudian masukkan kode berikut ini di dalamnya.
src/views/products/create.tsx
// import hook useState and Interface ChangeEvent, FormEvent dari react
import { FC, useState, ChangeEvent, FormEvent } from "react";
// import useNavigate dari react-router
import { useNavigate } 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 ProductCreate: 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();
// 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 storeProduct = async (e: FormEvent) => {
e.preventDefault();
// Membuat FormData
const formData = new FormData();
// Memasukkan data ke FormData
if (image) formData.append("image", image);
formData.append("title", title);
formData.append("description", description);
formData.append("price", price);
formData.append("stock", stock);
try {
// Kirim data ke API
await Api.post("/api/products", 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={storeProduct}>
<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"
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"
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"
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"
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 ProductCreate;
Dari penambahan kode di atas, pertama kita import Type FC
, hook useState
, Interface changeEvent
dan FormEvent
dari React.
// import hook useState and Interface ChangeEvent, FormEvent dari react
import { FC, useState, ChangeEvent, FormEvent } from "react";
Kemudian kita import hook useNavigate
dari React Router.
// import useNavigate dari react-router
import { useNavigate } from "react-router";
Dan kita import service API yang sudah pernah kita buat sebelumnya.
// import api dari folder api
import Api from "../../api";
Selanjutnya, kita membuat interface dengan nama Errors
. Interface ini akan digunakan untuk meng-handle response error dari Rest API.
interface Errors {
image?: string[];
title?: string[];
description?: string[];
price?: string[];
stock?: string[];
}
Di atas, setiap properti bersifat opsional (?
) dan berupa array string, yang bisa berisi pesan error dari server.
Dan di dalam function component ProductCreate
, kita membuat beberapa state yang nanti digunakan untuk menampung data dari form.
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>({});
Di atas untuk state price
dan stock
, kita menggunakan tipe string
karena FormData hanya mendukung string. Nantinya, sebelum dikirim ke API, nilai dari kedua state ini akan tetap dalam bentuk string agar kompatibel dengan FormData.
Untuk mempermudah dalam menggunakan hook useNavigate
, maka kita masukkan ke dalam sebuah variable.
//useNavigate
const navigate = useNavigate();
Kemudian kita buat function baru dengan nama handleFileChange
. Function ini yang digunakan untuk memasukkan file yang diambil dari komputer ke dalam state image
.
// Handle perubahan file
const handleFileChange = (e: ChangeEvent<HTMLInputElement>) => {
if (e.target.files && e.target.files[0]) {
setImage(e.target.files[0]);
}
};
Function handleFileChange
di atas akan dijalankan, ketika input file gambar di dalam form dipilih.
<input
type="file"
onChange={handleFileChange}
className="form-control"
/>
Setelah itu, kita buat function lagi dengan nama storeProduct
. Method ini akan dijalankan ketika form disubmit.
<form onSubmit={storeProduct}>
//...
</form>
// Handle submit form
const storeProduct = async (e: FormEvent) => {
//...
}
Di dalam method storePost
di atas, pertama kita inisialisasi FormData
. Karena kita akan melakukan upload gambar, maka kita harus menggunakan FormData
agar file bisa dikirim ke server.
//init FormData
const formData = new FormData();
Setelah berhasil di inisialisasi, langkah berikutnya adalah memasukkan data yang ada di dalam state ke dalam FormData
, yaitu dengan menggunakan append
.
// Memasukkan data ke FormData
if (image) formData.append("image", image);
formData.append("title", title);
formData.append("description", description);
formData.append("price", price);
formData.append("stock", stock);
Setelah data berhasil dimasukkan ke dalam FormData
, langkah berikutnya adalah melakukan kirim data menggunakan Rest API dengan bantuan Axios
, yaitu menggunakan method POST
.
// Kirim data ke API
await Api.post("/api/products", formData);
Jika proses insert dan upload data berhasil dilakukan di dalam server, maka kita akan redirect ke dalam halaman products index.
// Redirect ke halaman products
navigate("/products");
Tapi jika data gagal disimpan, maka kita akan memasukkan error response validasi ke dalam state yang bernama errors
.
// Set error
setErrors(error.response.data);
Dan untuk menampilkan error di dalam JSX, kita bisa menggunakan kode seperti berikut ini.
{errors.image && (
<div className="alert alert-danger mt-2">
{errors.image[0]}
</div>
)}
Langkah 2 - Konfigurasi Route Products Create
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";
// 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 />} />
</Routes>
);
};
export default RoutesIndex;
Dari perubahan kode di atas, kita import view products create.
// Import view ProductCreate
import ProductCreate from "../views/products/create";
Kemudian kita membuat konfigurasi route dengan path products/create
.
{/* Route untuk halaman create product */}
<Route path="/products/create" element={<ProductCreate />} />
Langkah 3 - Uji Coba Insert dan Upload di React
Silahkan teman-teman klik button ADD NEW PRODUCT
yang ada pada halaman products index atau juga bisa melalui link berikut ini http://localhost:5173/products/create, jika berhasil maka akan menampilkan halaman seperti berikut.

Silahkan klik button Save
tanpa mengisi data apapun di dalam form, maka kita akan mendapatkan error validasi yang dikirimkan oleh Laravel melaluio Rest API.

Sekarang, silahkan masukkan data yang diinginkan di dalam form dan teman-teman klik Save
. Jika berhasil maka kita akan diarahakan ke halaman products index dengan data yang berhasil disimpan.

Kesimpulan
Pada artikel ini, kita semua telah belajar bagaimana membuat proses insert dan upload data di React TypeScript menggunakan Rest API.
Pada artikel selanjutnya, kita semua akan belajar bagaimana cara melakukan proses edit dan update data di React TypeScript menggunakan Rest API.
Terima Kaish