Sinkronisasi CRUD LocalStorage dengan PHP & MySQL

By | 17 October 2025

Sebelumnya, kita sudah membuat aplikasi CRUD (Create, Read, Update, Delete) menggunakan JavaScript dan LocalStorage. Namun, LocalStorage hanya menyimpan data di browser pengguna, artinya tidak bisa dibagikan antar perangkat. Untuk mengatasinya dapat dilakukan dengan cara Sinkronisasi CRUD LocalStorage, yaitu kita akan menyinkronkan data LocalStorage ke server PHP & MySQL, sehingga:

  • Data tetap tersimpan secara permanen di database server.

  • Bisa diakses dari mana saja.

  • Dapat disinkronkan otomatis setiap kali data berubah.

Arsitektur Aplikasi

Proses kerja sinkronisasi:

  1. CRUD dilakukan secara lokal (cepat & responsif).

  2. Saat ada perubahan data, aplikasi akan mengirim update ke server PHP.

  3. PHP akan menyimpan atau memperbarui data di database MySQL.

  4. Saat halaman dimuat ulang, data dari database dikirim kembali ke LocalStorage.

Struktur Folder

project/
│
├── index.html
├── app.js
├── api/
│   ├── get.php
│   ├── save.php
│   ├── delete.php
│
└── db.php

Database dan Koneksi PHP

Buat Tabel MySQL

CREATE TABLE products (
  id INT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(100),
  price INT
);

File: db.php

<?php
$conn = new mysqli("localhost", "root", "", "tutorial_js");
if ($conn->connect_error) {
  die("Koneksi gagal: " . $conn->connect_error);
}
?>

API — Menampilkan Data (Read)

File: api/get.php

<?php
include "../db.php";

$result = $conn->query("SELECT * FROM products ORDER BY id DESC");
$data = [];

while ($row = $result->fetch_assoc()) {
  $data[] = $row;
}

echo json_encode($data);
?>

API — Menyimpan atau Memperbarui Data (Create/Update)

File: api/save.php

<?php
include "../db.php";

$data = json_decode(file_get_contents("php://input"), true);

$name = $conn->real_escape_string($data["name"]);
$price = (int)$data["price"];
$id = isset($data["id"]) ? (int)$data["id"] : 0;

if ($id > 0) {
  $conn->query("UPDATE products SET name='$name', price=$price WHERE id=$id");
} else {
  $conn->query("INSERT INTO products (name, price) VALUES ('$name', $price)");
}

echo json_encode(["status" => "success"]);
?>

API — Hapus Data (Delete)

File: api/delete.php

<?php
include "../db.php";

$id = (int)$_GET["id"];
$conn->query("DELETE FROM products WHERE id=$id");

echo json_encode(["status" => "deleted"]);
?>

Frontend HTML (index.html)

<h2> Produk (CRUD Sinkronisasi LocalStorage + PHP)</h2>

<form id="productForm">
  <input type="hidden" id="editIndex">
  <input type="text" id="name" placeholder="Nama Produk" required>
  <input type="number" id="price" placeholder="Harga Produk" required>
  <button type="submit">Simpan</button>
</form>

<table border="1" cellpadding="8" cellspacing="0">
  <thead>
    <tr>
      <th>No</th>
      <th>Nama</th>
      <th>Harga</th>
      <th>Aksi</th>
    </tr>
  </thead>
  <tbody id="tableBody"></tbody>
</table>

<script src="app.js"></script>

JavaScript — Sinkronisasi LocalStorage dan Server

File: app.js

const form = document.getElementById("productForm");
const nameInput = document.getElementById("name");
const priceInput = document.getElementById("price");
const tableBody = document.getElementById("tableBody");
const editIndex = document.getElementById("editIndex");

let products = JSON.parse(localStorage.getItem("products")) || [];

// Menampilkan data di tabel
function renderTable() {
  tableBody.innerHTML = "";
  products.forEach((p, i) => {
    const row = `
      <tr>
        <td>${i + 1}</td>
        <td>${p.name}</td>
        <td>Rp ${p.price.toLocaleString()}</td>
        <td>
          <button onclick="editProduct(${i})">Edit</button>
          <button onclick="deleteProduct(${p.id || i})">Hapus</button>
        </td>
      </tr>`;
    tableBody.insertAdjacentHTML("beforeend", row);
  });
  localStorage.setItem("products", JSON.stringify(products));
}

// Ambil data dari server saat pertama kali load
async function fetchFromServer() {
  const res = await fetch("api/get.php");
  const data = await res.json();
  products = data;
  localStorage.setItem("products", JSON.stringify(data));
  renderTable();
}

// Tambah atau edit data
form.addEventListener("submit", async (e) => {
  e.preventDefault();

  const data = {
    name: nameInput.value.trim(),
    price: parseInt(priceInput.value.trim()),
    id: editIndex.value ? parseInt(editIndex.value) : 0,
  };

  // Simpan ke server
  await fetch("api/save.php", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(data),
  });

  await fetchFromServer(); // Refresh data
  form.reset();
  editIndex.value = "";
});

// Edit
function editProduct(index) {
  const p = products[index];
  nameInput.value = p.name;
  priceInput.value = p.price;
  editIndex.value = p.id;
}

// Hapus data
async function deleteProduct(id) {
  if (confirm("Hapus data ini?")) {
    await fetch(`api/delete.php?id=${id}`);
    await fetchFromServer();
  }
}

fetchFromServer();

Cara Kerja Sinkronisasi

Prosesnya berjalan otomatis:

  1. Saat data diubah → dikirim ke server via fetch().

  2. Server (PHP) menyimpan ke MySQL.

  3. Halaman memuat ulang data terbaru → disimpan lagi ke LocalStorage.

  4. Jika offline, data masih tersimpan di LocalStorage dan bisa disinkronkan lagi saat online.

Kelebihan Pendekatan Ini

✅ Data tetap tersedia offline (LocalStorage).
Tersinkron otomatis saat online.
✅ Cepat dan ringan untuk web interaktif.
✅ Cocok untuk progressive web app (PWA).

Ide Pengembangan

Kamu bisa menambahkan:

  • Deteksi koneksi offline/online.

  • Tombol “Sinkronkan Sekarang”.

  • Login user agar data per pengguna berbeda.

  • Backup otomatis ke cloud.

Kesimpulan

Dengan sinkronisasi antara LocalStorage dan PHP MySQL, kamu mendapatkan keunggulan dari dua sisi:

  • Kecepatan aplikasi lokal tanpa delay.

  • Keamanan dan persistensi data di server.

Langkah ini adalah fondasi penting sebelum membangun aplikasi web offline-first modern seperti POS, To-Do App, dan Dashboard Admin.