Composables: Logika yang Bisa Dipakai Ulang
Membuat composable (fungsi useXxx) yang membungkus state reaktif + logika, parameter & return, state independen per pemakaian, dan contoh nyata.
Masalah: logika yang sama di banyak komponen
Komponen A butuh penghitung (tambah, kurang, reset). Komponen B juga. Menyalin kode yang sama ke dua tempat mengundang bug. Untuk tampilan yang berulang kita memakai komponen; untuk logika yang berulang, Vue memakai composable.
Composable adalah fungsi biasa yang memakai API reaktivitas Vue (ref, computed, watch, lifecycle) lalu mengembalikan state dan fungsi yang siap dipakai. Konvensi nama: diawali use (useHitung, useMouse, useFetch).
Contoh: useHitung
// composables/useHitung.js
import { ref, computed } from 'vue'
export function useHitung(awal = 0) {
const n = ref(awal)
const ganda = computed(() => n.value * 2)
function tambah() { n.value++ }
function kurang() { n.value-- }
function reset() { n.value = awal }
return { n, ganda, tambah, kurang, reset }
}
Pemakaian di komponen:
<script setup>
import { useHitung } from './composables/useHitung.js'
const { n, ganda, tambah, reset } = useHitung(10)
</script>
<template>
<button @click="tambah">{{ n }} (x2 = {{ ganda }})</button>
<button @click="reset">Reset</button>
</template>
Memecah hasil dengan destructuring di sini aman, karena yang dikembalikan adalah ref (bukan objek reactive yang dipecah).
Setiap pemakaian punya state sendiri
const a = useHitung(0)
const b = useHitung(100)
a.tambah() // a.n = 1, b.n tetap 100
Setiap pemanggilan membuat ref baru, jadi dua penghitung independen. (Untuk state yang dibagi bersama, simpan ref di luar fungsi atau pakai Pinia — bab 22.)
Composable yang memakai lifecycle
// useUkuranLayar.js
import { ref, onMounted, onUnmounted } from 'vue'
export function useUkuranLayar() {
const lebar = ref(window.innerWidth)
const perbarui = () => (lebar.value = window.innerWidth)
onMounted(() => window.addEventListener('resize', perbarui))
onUnmounted(() => window.removeEventListener('resize', perbarui))
return { lebar }
}
Lihat bagaimana logika "pasang dan bersihkan listener" terbungkus rapi. Komponen yang memakainya tak perlu tahu detailnya.
Menerima argumen reaktif
import { toValue, watchEffect } from 'vue'
export function useJudul(teks) { // teks boleh string, ref, atau getter
watchEffect(() => { document.title = toValue(teks) })
}
useJudul(() => `Keranjang (${jumlah.value})`)
Composable vs yang lain
| Alat | Membungkus |
|---|---|
| Komponen | Tampilan + logikanya |
| Composable | Logika reaktif tanpa tampilan |
| Fungsi utilitas biasa | Logika murni tanpa state reaktif (mis. format tanggal) |
Aturan emas
- Panggil composable sinkron di dalam
setup(atau composable lain). - Kembalikan objek berisi ref/fungsi agar fleksibel dipecah.
- Bersihkan efek samping di
onUnmounted. - Pustaka VueUse menyediakan ratusan composable siap pakai (useMouse, useLocalStorage, useDark, …).
Kesalahan umum
- Memanggil composable di dalam kondisi/callback asinkron (kehilangan konteks komponen).
- Lupa
returnsehingga hasilnyaundefined. - Mengira dua pemanggilan saling berbagi state.