- Writing JavaScript Views the Hard Way : artikel yang menjelaskan cara membangun view hanya dengan JavaScript murni tanpa framework
- Melalui pendekatan imperatif langsung, pendekatan ini memberikan performa, kemudahan perawatan, dan portabilitas
- Pembaruan state dan pembaruan DOM dipisahkan dengan jelas, serta mengikuti aturan penamaan yang ketat dan pola struktural sesuai perannya
- Pendekatan ini mudah di-debug, menjamin kompatibilitas dengan semua browser, dan memiliki keunggulan besar berupa 0 dependencies
- Meski bisa terasa sulit bagi pemula, mempelajarinya memberi pemahaman mendalam tentang cara kerja sistem yang sebenarnya
Menulis view JavaScript dengan 'Hard Way'
Apa ini?
- Pendekatan ini adalah pola untuk menyusun view hanya dengan JavaScript tanpa framework seperti React, Vue, lit-html
- Ini bukan library atau alat tertentu, melainkan pola penulisan kode itu sendiri, yang membantu mencegah masalah spaghetti code
- Dengan menggunakan pendekatan imperatif langsung, abstraksi dikurangi dan intuisi ditingkatkan
Kelebihan dibanding framework
- Performa: karena berupa kode imperatif, ia berjalan tanpa komputasi yang tidak perlu dan cocok untuk hot path maupun cold path
- 0 dependencies: bebas dari masalah upgrade library atau kompatibilitas
- Portabilitas: kode yang ditulis dapat dipindahkan ke framework mana pun
- Kemudahan perawatan: struktur bagian yang jelas dan aturan penamaan memudahkan menemukan lokasi kode
- Dukungan browser: kompatibel dengan sebagian besar browser mulai IE9 ke atas, dan bahkan IE6 dapat didukung dengan beberapa penyesuaian
- Kemudahan debugging: memberikan stack trace yang dangkal tanpa lapisan perantara
- Struktur fungsional: meski bukan immutable, semua komponen disusun berbasis fungsi
Penjelasan struktur
Struktur keseluruhan
- Terdiri dari fungsi
template → clone() → init()
- Fungsi
init() membuat satu instance view yang mencakup variabel state, referensi DOM, fungsi update, event listener, dan sebagainya
Contoh struktur kode (Hello World)
const template = document.createElement('template');
template.innerHTML = `<div>Hello <span id="name">world</span>!</div>`;
function clone() {
return document.importNode(template.content, true);
}
function init() {
let frag = clone();
let nameNode = frag.querySelector('#name');
let name;
function setNameNode(value) {
nameNode.textContent = value;
}
function setName(value) {
if(name !== value) {
name = value;
setNameNode(value);
}
}
function update(data = {}) {
if(data.name) setName(data.name);
return frag;
}
return update;
}
Susunan di dalam fungsi init()
1. Variabel DOM
frag adalah potongan template yang dibuat dari clone()
- Elemen di dalamnya direferensikan dengan
querySelector(), dan nama variabel menggunakan bentuk fooNode
2. DOM view
- Bagian yang memuat view lain (sub-view yang dapat digunakan ulang)
- Contoh:
let updateChildView = childView();
- Fungsi pembaruan view diberi nama dalam bentuk
updateFoo
3. Variabel state
- Nilai data yang dapat berubah di dalam view
- Untuk membuat pembaruan DOM efisien, perubahan DOM hanya dilakukan saat diperlukan dengan membandingkan nilai saat ini
4. Fungsi pembaruan DOM
- Digunakan saat mengubah status elemen DOM
- Contoh:
function setNameNode(value) {
nameNode.textContent = value;
}
- Manipulasi DOM wajib dilakukan hanya di dalam fungsi ini
5. Fungsi pembaruan state
- Mencakup logika perubahan state dan penerapannya ke DOM
- Nilai yang tidak berubah diabaikan untuk mencegah perubahan DOM yang tidak perlu
- Contoh:
function setName(value) {
if(name !== value) {
name = value;
setNameNode(value);
}
}
Fungsi template dan clone()
template
- Membuat struktur HTML statis dengan elemen
<template>
- Tidak langsung dimasukkan ke DOM, melainkan disalin lewat clone
clone()
- Menggandakan dengan
document.importNode(template.content, true)
- Jika perlu, elemen root dapat dikembalikan menggunakan
.firstElementChild
Cara interaksi
Aliran data induk → anak
- Induk memanggil
init() milik anak untuk mendapatkan fungsi update, lalu memanggilnya dalam bentuk update({ name: 'foo' })
Penyebaran data berbasis event
- Secara default mengikuti model props down, events up
- View bawahan berkomunikasi dengan mengirim event ke atas
Perbandingan dengan React
constructor() (React) → init() (Hard Way)
- Bertanggung jawab atas pengaturan awal komponen
render() (React) → update(data) (Hard Way)
- Berperan dalam menyegarkan tampilan dan memperbarui UI
this.setState() (React) → setX(value) (Hard Way)
- Digantikan oleh cara mengatur nilai state secara langsung
props (React) → nilai yang dikirim melalui update(data) (Hard Way)
- Cara menangani data yang diteruskan dari komponen induk
- JSX / Virtual DOM (React) → template HTML + DOM API (Hard Way)
- Menggunakan template dan manipulasi DOM manual alih-alih UI deklaratif
Kesimpulan
- Dibanding framework yang sudah familier, pendekatan ini memang memiliki hambatan awal yang lebih tinggi, tetapi memiliki kekuatan berikut:
- Optimisasi performa
- Kontrol penuh
- Pemahaman mendalam melalui proses belajar
- Dengan pemisahan fungsi berdasarkan peran dan aturan penamaan, pendekatan ini memungkinkan penyusunan UI yang tetap mudah dirawat tanpa framework
Kompatibilitas
- Contoh terbaru menggunakan API untuk browser modern, tetapi bahkan hingga IE9 ke bawah pun dapat didukung melalui pengganti berbasis fungsi
- Dapat diperluas hingga IE6 dengan menggunakan pendekatan meneruskan fungsi lewat props alih-alih event
3 komentar
Pada akhirnya kembali ke web component..
Selamat. Satu lagi framework js telah lahir.
Komentar Hacker News
Ini mungkin bidah bagi banyak developer JS, tetapi saya menganggap variabel
statesebagai anti-patternvalue/textContent/checkedpada elemen DOM sebagai satu-satunya sumber kebenaranDokumentasinya mengatakan pendekatan ini sangat mudah dirawat, tetapi saya tidak setuju
Belakangan ini saya menulis aplikasi dengan TypeScript 'vanilla' murni bersama vite, dan makin mempertanyakan praktik 'terbaik' frontend
Pendekatan ini mengingatkan saya pada library backbone js yang lama
Saya baru-baru ini memikirkan sesuatu yang mirip, tetapi tidak menggunakan elemen template
innerHTMLelemen yang ada atau membuat elemendivbaru untuk menaruhnyaKode ini terlihat persis seperti kode pembaruan manual yang ingin digantikan oleh library view reaktif
Saya sudah memprogram sekitar 20 tahun tetapi belum pernah benar-benar terbiasa dengan framework frontend
Saya menggunakan helper yang mirip dengan
React.createElementSaya sedang mengerjakan deja-vu.junglecoder.com sebagai upaya membangun toolkit JS untuk alat berbasis HTML
grab/patchlumayan bagusDi pekerjaan resmi pertama saya setelah lulus kuliah, saya membuat versi web dari software Delphi