Membuat Computed Property dan Watcher Otomatis di JavaScript Tanpa Framework

By | 19 October 2025

Dalam pengembangan aplikasi modern, sering kali kita ingin memiliki data yang otomatis terhitung ulang saat nilai lain berubah. Misalnya, ketika pengguna mengetik nama depan dan nama belakang, kita ingin menampilkan nama lengkap tanpa harus memanggil fungsi manual. Konsep inilah yang dikenal sebagai computed property di JavaScript.

Selain itu, terkadang kita ingin menjalankan aksi tertentu setiap kali nilai berubah, seperti menyimpan data ke localStorage atau memperbarui log aktivitas. Untuk kebutuhan seperti ini, kita memanfaatkan watcher otomatis.
Menariknya, semua ini bisa kita buat sendiri hanya dengan JavaScript murni (vanilla JS) tanpa framework seperti Vue atau React, menggunakan kombinasi Proxy dan Reflect API.

Konsep Computed Property dan Watcher

Sebelum masuk ke implementasi, mari pahami dua konsep penting ini:

Computed Property
Nilainya tidak disimpan langsung, melainkan dihitung ulang secara otomatis berdasarkan data lain.
Contoh:

fullName = `${firstName} ${lastName}`;

Watcher Otomatis
Merupakan fungsi yang dipanggil otomatis setiap kali data tertentu berubah. Misalnya:

  • Menyimpan data ke localStorage
  • Menampilkan pesan log di console
  • Memperbarui elemen DOM

Dengan menggabungkan keduanya, kita bisa membuat sistem reaktif layaknya framework modern, namun tetap ringan dan mudah dipahami.

Langkah 1: Membuat Reactive Data dengan Proxy

Kita mulai dengan membuat data reactive yang bisa terdeteksi setiap kali nilainya berubah:

const data = {
  firstName: "John",
  lastName: "Doe"
};

const watchers = {}; // daftar watcher untuk properti tertentu

Lalu kita bungkus dengan Proxy() agar bisa memantau perubahan:

const reactiveData = new Proxy(data, {
  get(target, key) {
    return target[key];
  },
  set(target, key, value) {
    target[key] = value;
    triggerWatcher(key, value);
    updateComputed();
    render();
    return true;
  }
});

Langkah 2: Menambahkan Computed Property

Sekarang kita buat sistem agar computed property seperti fullName bisa dihitung otomatis saat data berubah.

const computed = {
  fullName() {
    return `${reactiveData.firstName} ${reactiveData.lastName}`;
  }
};

function updateComputed() {
  for (let key in computed) {
    reactiveData[key] = computed[key](); // hitung ulang semua computed property
  }
}

Dengan ini, setiap kali firstName atau lastName berubah, maka fullName akan otomatis diperbarui.

Langkah 3: Membuat Watcher Otomatis

Watcher digunakan untuk mengeksekusi fungsi tertentu saat nilai berubah.

function watch(property, callback) {
  watchers[property] = callback;
}

function triggerWatcher(property, value) {
  if (watchers[property]) {
    watchers[property](value);
  }
}

Contoh penggunaannya:

watch("firstName", (val) => {
  console.log("Nama depan berubah menjadi:", val);
});

Langkah 4: Render dan Integrasi ke DOM

Sekarang kita sambungkan semuanya dengan UI agar data bisa tampil dan diperbarui secara otomatis.

<div>
  <label>Nama Depan:</label>
  <input type="text" id="firstName">
</div>
<div>
  <label>Nama Belakang:</label>
  <input type="text" id="lastName">
</div>
<hr>
<p>Nama Lengkap: <span id="fullName"></span></p>

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

Dan fungsi render() di app.js:

function render() {
  document.querySelector("#firstName").value = reactiveData.firstName;
  document.querySelector("#lastName").value = reactiveData.lastName;
  document.querySelector("#fullName").innerText = reactiveData.fullName;
}

document.querySelector("#firstName").addEventListener("input", e => {
  reactiveData.firstName = e.target.value;
});

document.querySelector("#lastName").addEventListener("input", e => {
  reactiveData.lastName = e.target.value;
});

updateComputed();
render();

Langkah 5: Menyimpan ke LocalStorage (Contoh Watcher)

Sekarang kita tambahkan watcher untuk menyimpan data setiap kali nama berubah:

watch("firstName", () => saveToLocal());
watch("lastName", () => saveToLocal());

function saveToLocal() {
  localStorage.setItem("user", JSON.stringify({
    firstName: reactiveData.firstName,
    lastName: reactiveData.lastName
  }));
}

Dengan ini, setiap kali user mengetik, data akan otomatis tersimpan ke localStorage tanpa perlu klik tombol apa pun.

Langkah 6: Menggunakan Reflect untuk Keamanan dan Fleksibilitas

Kita bisa mengganti target[key] = value menjadi:

Reflect.set(target, key, value);

Reflect memberikan kontrol yang lebih aman, misalnya saat properti tidak dapat ditulis atau jika kita ingin menangani error dengan elegan.

Hasil Akhir

Kini kamu memiliki sistem reactive lengkap:

  • Data otomatis sinkron dengan UI

  • Computed property seperti fullName dihitung ulang setiap kali data berubah

  • Watcher otomatis yang bisa menyimpan data, log, atau menjalankan aksi lain

Pengembangan Lebih Lanjut

Kamu bisa memperluas sistem ini dengan:

  1. Menambahkan computed property kompleks seperti total harga, sisa waktu, atau status dinamis.

  2. Membuat dependency tracking agar hanya computed yang terkait yang diperbarui.

  3. Mengintegrasikan dengan renderer untuk update DOM otomatis tanpa re-render keseluruhan.

  4. Membuat binding directive seperti v-model di Vue untuk input otomatis.

Kesimpulan

Dengan memahami konsep computed property di JavaScript dan watcher otomatis, kamu telah mempelajari fondasi dari sistem reactive modern yang digunakan framework besar. Kelebihannya, kamu dapat menerapkannya dengan JavaScript murni, ringan, dan mudah disesuaikan sesuai kebutuhan proyekmu.