Halo teman-teman semuanya, pada artikel sebelumnya kita semua telah belajar bagaimana melakukan proses data fetching menggunakan useQuery
dari TanStack Query di dalam React.
Dan pada artikel kali ini, kita semua akan belajar melakukan proses insert data menggunakan hook useMutation
dari TanStack Query di React.
Langkah 1 - Insert Data Dengan useMutation
Silahkan teman-teman buat file baru dengan nama create.jsx
di dalam folder src/views/products
, kemudian masukkan kode berikut ini di dalamnya.
src/views/products/create.jsx
//import hook useState
import { useState } from "react";
//import hook useNavigate
import { useNavigate } from "react-router";
//import hook useMutation
import { useMutation } from "@tanstack/react-query";
//import service Api
import Api from "../../api";
const ProductCreate = () => {
// State for image, title, description, price, stock and errors
const [image, setImage] = useState(null);
const [title, setTitle] = useState("");
const [description, setDescription] = useState("");
const [price, setPrice] = useState("");
const [stock, setStock] = useState("");
const [errors, setErrors] = useState({});
// Initialize useNavigate
const navigate = useNavigate();
// Function to handle file change
const handleFileChange = (e) => {
if (e.target.files && e.target.files[0]) {
setImage(e.target.files[0]);
}
};
// Initialize useMutation
const mutationProduct = useMutation({
//mutation function
mutationFn: async (formData) => {
// Call the API to store the product
const response = await Api.post("/api/products", formData);
return response.data;
},
onSuccess: () => {
// Redirect to the product index page
navigate("/products");
},
onError: (error) => {
// set errors if there is an error
setErrors(error.response.data);
},
});
// Function to handle form submission
const storeProduct = (e) => {
e.preventDefault();
//initialize formData
const formData = new FormData();
//append data to formData
if (image) formData.append("image", image);
formData.append("title", title);
formData.append("description", description);
formData.append("price", price);
formData.append("stock", stock);
// Call the mutationProduct function
mutationProduct.mutate(formData);
};
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}>
{/* Input image */}
<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>
{/* Input title */}
<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>
{/* Input description */}
<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>
{/* Input price & stock */}
<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"
/>
{errors.price && (
<div className="alert alert-danger mt-2">{errors.price[0]}</div>
)}
</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"
/>
{errors.stock && (
<div className="alert alert-danger mt-2">{errors.stock[0]}</div>
)}
</div>
</div>
</div>
<button
type="submit"
className="btn btn-md btn-primary rounded-5 shadow border-0"
disabled={mutationProduct.isPending}
>
{mutationProduct.isPending ? "Saving..." : "Save"}
</button>
</form>
</div>
</div>
</div>
</div>
</div>
);
};
export default ProductCreate;
Dari penambahan kode di atas, pertama kita import hook useState
dari React.
//import hook useState
import { useState } from "react";
Kemudian kita import hook useNavigate
dari React Router.
//import hook useNavigate
import { useNavigate } from "react-router";
Dan kita import juga hook useMutation
dari TanStack Query.
//import hook useMutation
import { useMutation } from "@tanstack/react-query";
Terakhir, kita import service API.
//import service Api
import Api from "../../api";
Di dalam function component ProductCreate
kita membuat beberapa state yang nanti digunakan untuk menyimpan data yang dikirimkan dari form.
// State for image, title, description, price, stock and errors
const [image, setImage] = useState(null);
const [title, setTitle] = useState("");
const [description, setDescription] = useState("");
const [price, setPrice] = useState("");
const [stock, setStock] = useState("");
const [errors, setErrors] = useState({});
Kemudian kita inisialisasi navigate
.
// Initialize useNavigate
const navigate = useNavigate();
Selanjutnya, kita membuat function yang bernama handleFileChange
. Fungsi ini akan dipanggil saat kita memilih file di dalam komputer.
<input type="file" onChange={handleFileChange} className="form-control" />
// Function to handle file change
const handleFileChange = (e) => {
if (e.target.files && e.target.files[0]) {
setImage(e.target.files[0]);
}
};
Setelah itu, kita inisialisasi hook useMutation
dengan nama mutationProduct
.
// Initialize useMutation
const mutationProduct = useMutation({
//...
})
Di dalamnya, ada yang namanya mutationFn
, yaitu fungsi utama yang akan dipanggil ketika kita menjalankan mutationProduct.mutate(...)
.
//mutation function
mutationFn: async (formData) => {
// Call the API to store the product
const response = await Api.post("/api/products", formData);
return response.data;
},
Pada mutationFn
di atas menerima parameter wajib yang bernama formData
dan di dalamnya kita memanggil REST API untuk proses insert data ke backend.
Jika berhasil, maka akan memanggil onSuccess
, yang mana di dalamnya kita redirect ke halaman products index.
onSuccess: () => {
// Redirect to the product index page
navigate("/products");
},
Jika gagal, maka akan memanggil onError
dan di dalamnya kita set response data dari backend ke dalam state errors
.
onError: (error) => {
// set errors if there is an error
setErrors(error.response.data);
},
Selanjutnya, kita membuat function yang bernama storeProduct
. Fungsi ini akan dijalankan ketika form disubmit.
<form onSubmit={storeProduct}>
//...
</form>
const storeProduct = (e) => {
//...
}
Di dalam function di atas, kita melakukan inisialisasi FormData
dan melakukan append data di dalamnya.
//initialize formData
const formData = new FormData();
//append data to formData
if (image) formData.append("image", image);
formData.append("title", title);
formData.append("description", description);
formData.append("price", price);
formData.append("stock", stock);
Setelah itu, kita panggil mutationProduct
dan memanggil fungsi mutate
dengan mengirimkan formData
di dalamnya.
// Call the mutationProduct function
mutationProduct.mutate(formData);
Langkah 2 - Konfigurasi Route Products Create
Silahkan teman-teman buka file src/routes/index.jsx
, kemudian ubah kode-nya menjadi seperti berikut ini.
src/routes/index.jsx
// 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 (Functional Component)
const RoutesIndex = () => {
return (
<Routes>
{/* Route untuk halaman utama */}
<Route path="/" element={<Home />} />
{/* Route untuk halaman produk */}
<Route path="/products" element={<ProductIndex />} />
{/* Route untuk halaman tambah produk */}
<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 kali ini, kita telah belajar menggunakan useMutation
untuk proses insert data. Sehingga kode menjadi lebih rapi dan terstruktur.
Pada artikel selanjutnya, kita akan belajar bagaimana cara melakukan proses edit dan update data menggunakan useMutation
dari TanStack Query.
Terima Kasih