Vue 3 Reactivity Transform di 2026: $ref, $computed dan Pertanyaan Interview

Panduan mendalam tentang Reactivity Transform Vue 3 meliputi $ref, $computed, dan pertanyaan interview yang sering diajukan untuk developer Vue senior.

Vue 3 Reactivity Transform $ref dan $computed

Reactivity Transform merupakan fitur eksperimental Vue 3 yang bertujuan menyederhanakan penggunaan reactive state dengan menghilangkan kebutuhan .value pada ref. Meskipun fitur ini telah dihapus dari Vue core sejak versi 3.4, pemahaman tentang konsep dan alternatifnya tetap relevan dalam interview Vue developer karena menunjukkan kedalaman pengetahuan tentang sistem reaktivitas Vue.

Status Reactivity Transform

Reactivity Transform ($ref, $computed) telah dihapus dari Vue 3.4 ke atas. Vue Macros menyediakan implementasi komunitas bagi tim yang masih membutuhkannya. Pemahaman konsep ini tetap bernilai untuk interview karena menunjukkan pengetahuan tentang evolusi Vue.

Memahami Masalah yang Dipecahkan Reactivity Transform

Sistem reaktivitas Vue 3 berbasis pada objek ref dan reactive. Ketika menggunakan ref, developer harus mengakses nilai melalui properti .value di dalam script, sementara di template akses langsung tanpa .value dimungkinkan karena unwrapping otomatis.

typescript
import { ref, computed } from 'vue'

// Pendekatan standar dengan .value
const count = ref(0)
const doubled = computed(() => count.value * 2)

function increment() {
  count.value++
  console.log(doubled.value)
}

Reactivity Transform menghilangkan boilerplate .value dengan macro compiler yang mentransformasi kode pada waktu build.

typescript
// Dengan Reactivity Transform (deprecated)
let count = $ref(0)
const doubled = $computed(() => count * 2)

function increment() {
  count++
  console.log(doubled)
}

Cara Kerja $ref dan $computed

Macro $ref mendeklarasikan variabel reaktif yang dapat digunakan seperti variabel JavaScript biasa. Compiler Vue mentransformasi kode ini menjadi penggunaan ref standar dengan .value yang tepat.

typescript
// Kode sumber dengan $ref
let username = $ref('')
let isValid = $computed(() => username.length >= 3)

function updateUsername(value: string) {
  username = value
}

// Hasil transformasi compiler
import { ref, computed } from 'vue'

const username = ref('')
const isValid = computed(() => username.value.length >= 3)

function updateUsername(value: string) {
  username.value = value
}

Macro $$ untuk Escape Ref

Macro $$ memungkinkan mengakses objek ref yang mendasari ketika diperlukan, misalnya saat passing ref ke composable atau watch.

typescript
import { watch } from 'vue'

let count = $ref(0)

// Menggunakan $$ untuk mendapatkan ref object
watch($$(count), (newVal, oldVal) => {
  console.log(`Count berubah dari ${oldVal} ke ${newVal}`)
})

// Passing ref ke composable
function useDoubled(countRef: Ref<number>) {
  return computed(() => countRef.value * 2)
}

const doubled = useDoubled($$(count))

Reactive Props Destructure

Vue 3.5 memperkenalkan destructuring props reaktif sebagai fitur stabil, menggantikan sebagian fungsionalitas Reactivity Transform untuk props.

vue
<script setup lang="ts">
// Vue 3.5+ reactive props destructure
const { count = 0, title } = defineProps<{
  count?: number
  title: string
}>()

// count dan title tetap reaktif
const doubled = computed(() => count * 2)
</script>

<template>
  <h1>{{ title }}</h1>
  <p>Count: {{ count }}, Doubled: {{ doubled }}</p>
</template>

Sebelum Vue 3.5, destructuring props memutus reaktivitas dan memerlukan toRefs:

Sebelum Vue 3.5typescript
const props = defineProps<{ count: number }>()
const { count } = toRefs(props) // Diperlukan untuk menjaga reaktivitas

Implementasi Alternatif dengan Vue Macros

Vue Macros adalah koleksi macro yang dikelola komunitas, menyediakan fungsionalitas Reactivity Transform dan fitur tambahan lainnya.

vite.config.tstypescript
import Vue from '@vitejs/plugin-vue'
import VueMacros from 'unplugin-vue-macros/vite'

export default defineConfig({
  plugins: [
    VueMacros({
      plugins: {
        vue: Vue(),
      },
    }),
  ],
})
vue
<script setup lang="ts">
// Dengan Vue Macros
let count = $ref(0)
let items = $ref<string[]>([])

const total = $computed(() => items.length)
const isEmpty = $computed(() => total === 0)

function addItem(item: string) {
  items = [...items, item]
  count++
}
</script>

Pattern Modern Tanpa Reactivity Transform

Pendekatan yang direkomendasikan di Vue 3.5 menggunakan fitur built-in tanpa memerlukan macro eksternal.

vue
<script setup lang="ts">
import { ref, computed, watch } from 'vue'

// Konvensi penamaan: gunakan suffix Ref untuk kejelasan
const countRef = ref(0)
const itemsRef = ref<string[]>([])

// Computed properties
const total = computed(() => itemsRef.value.length)
const isEmpty = computed(() => total.value === 0)

// Composable dengan reactive state
function useCounter(initialValue = 0) {
  const count = ref(initialValue)
  
  const increment = () => count.value++
  const decrement = () => count.value--
  const reset = () => count.value = initialValue
  
  return {
    count,
    increment,
    decrement,
    reset
  }
}

const { count, increment, decrement } = useCounter(10)
</script>

Perbandingan ref vs reactive

Pemahaman kapan menggunakan ref versus reactive sering muncul dalam interview Vue.

typescript
import { ref, reactive, toRefs } from 'vue'

// ref: untuk primitive values dan single values
const count = ref(0)
const name = ref('Vue')
const isLoading = ref(false)

// reactive: untuk objects dengan multiple properties
const state = reactive({
  user: null as User | null,
  posts: [] as Post[],
  pagination: {
    page: 1,
    perPage: 10
  }
})

// Destructure reactive object dengan toRefs
const { user, posts } = toRefs(state)

// Keunggulan ref:
// 1. Dapat di-reassign sepenuhnya
// 2. Dapat di-pass ke functions tanpa kehilangan reaktivitas
// 3. Lebih predictable dengan TypeScript

// Keunggulan reactive:
// 1. Tidak perlu .value untuk nested access
// 2. Lebih natural untuk complex state objects
// 3. Automatic unwrapping di template

Advanced Reactivity Patterns

Pattern-pattern lanjutan yang sering ditanyakan dalam interview senior Vue developer.

Custom Ref dengan Validasi

typescript
import { customRef } from 'vue'

function useDebouncedRef<T>(value: T, delay = 300) {
  let timeout: ReturnType<typeof setTimeout>
  
  return customRef<T>((track, trigger) => ({
    get() {
      track()
      return value
    },
    set(newValue: T) {
      clearTimeout(timeout)
      timeout = setTimeout(() => {
        value = newValue
        trigger()
      }, delay)
    }
  }))
}

// Penggunaan
const searchQuery = useDebouncedRef('', 500)

Shallow Reactivity untuk Performa

typescript
import { shallowRef, shallowReactive, triggerRef } from 'vue'

// shallowRef: hanya level pertama yang reaktif
const largeList = shallowRef<Item[]>([])

function updateList(items: Item[]) {
  largeList.value = items // Triggers update
}

function mutateItem(index: number) {
  largeList.value[index].name = 'Updated'
  triggerRef(largeList) // Manual trigger diperlukan
}

// shallowReactive: hanya properties level pertama yang reaktif
const config = shallowReactive({
  theme: 'dark',
  settings: { /* nested tidak reaktif */ }
})

Siap menguasai wawancara Vue.js / Nuxt.js Anda?

Berlatih dengan simulator interaktif, flashcards, dan tes teknis kami.

Pertanyaan Interview Vue Reactivity

Pertanyaan 1: Jelaskan perbedaan antara ref dan reactive

Jawaban yang diharapkan: ref membungkus nilai apapun (primitive atau object) dalam objek dengan properti .value, sedangkan reactive membuat proxy reaktif dari object. ref lebih fleksibel karena dapat menampung primitive dan dapat di-reassign sepenuhnya. reactive lebih ergonomis untuk complex nested objects tapi tidak dapat di-reassign dan kehilangan reaktivitas jika di-destructure tanpa toRefs.

Pertanyaan 2: Mengapa Reactivity Transform dihapus dari Vue core?

Jawaban yang diharapkan: Tim Vue memutuskan menghapus Reactivity Transform karena beberapa alasan: menambah kompleksitas mental dengan mencampur dua model reaktivitas, memerlukan tooling khusus yang tidak selalu tersedia, dan membuat debugging lebih sulit karena kode yang ditulis berbeda dengan kode yang dijalankan. Fitur reactive props destructure di Vue 3.5 mengatasi use case paling umum tanpa memerlukan macro global.

Pertanyaan 3: Bagaimana cara mempertahankan reaktivitas saat destructuring?

typescript
// Pertanyaan: Fix kode ini agar reaktif
const state = reactive({ count: 0, name: 'Vue' })
const { count, name } = state // Tidak reaktif!

// Jawaban:
import { toRefs } from 'vue'
const state = reactive({ count: 0, name: 'Vue' })
const { count, name } = toRefs(state) // Sekarang reaktif

// Atau gunakan computed untuk derived values
const count = computed(() => state.count)

Pertanyaan 4: Kapan menggunakan shallowRef vs ref?

Jawaban yang diharapkan: Gunakan shallowRef ketika bekerja dengan large objects atau arrays yang sering di-replace secara keseluruhan tetapi jarang dimutasi secara internal. Ini menghindari overhead dari deep reactivity tracking. Contoh use case: response API besar, large datasets untuk tabel, atau state yang di-manage oleh external library.

Pertanyaan 5: Implementasikan computed writable

typescript
import { ref, computed } from 'vue'

const firstName = ref('John')
const lastName = ref('Doe')

const fullName = computed({
  get() {
    return `${firstName.value} ${lastName.value}`
  },
  set(value: string) {
    const parts = value.split(' ')
    firstName.value = parts[0] || ''
    lastName.value = parts.slice(1).join(' ') || ''
  }
})

// Penggunaan
fullName.value = 'Jane Smith' // firstName = 'Jane', lastName = 'Smith'

Best Practices Reaktivitas Vue 3

  1. Preferensi ref untuk composables: Kembalikan ref dari composables karena lebih mudah di-destructure dan tetap reaktif.

  2. Gunakan readonly untuk data yang tidak boleh dimutasi: readonly(state) mencegah mutasi tidak disengaja.

  3. Hindari deep reactivity yang tidak perlu: Gunakan shallowRef atau markRaw untuk data yang tidak perlu reaktif.

  4. Konsisten dengan konvensi penamaan: Tambahkan suffix seperti Ref atau State untuk kejelasan.

  5. Leverage TypeScript: Definisikan types untuk ref generics untuk mencegah runtime errors.

Kesimpulan

Meskipun Reactivity Transform telah dihapus dari Vue core, memahami konsep di baliknya memberikan insight berharga tentang sistem reaktivitas Vue. Fitur-fitur modern seperti reactive props destructure di Vue 3.5 menyediakan ergonomi yang lebih baik tanpa kompleksitas tambahan dari macro compiler. Dalam interview, kemampuan menjelaskan trade-off dari berbagai pendekatan reaktivitas menunjukkan pemahaman mendalam tentang Vue internals.

Tantangan harian

Bisakah kamu menemukan bug di Vue.js / Nuxt.js?

Satu potongan kode nyata, satu bug tersembunyi, satu percobaan per hari. Tanpa akun untuk mencoba.

Anthony Fillion-Maillet

Ditulis oleh

Anthony Fillion-Maillet

Pendiri SharpSkill

Developer fullstack selama lebih dari 10 tahun. Ia menjalankan SharpSkill dan bertanggung jawab atas semua yang diterbitkan di sini.

Diperbarui 9 September 2026

Tag

#vue
#vue 3
#reactivity
#composition api
#interview

Bagikan

Artikel terkait