Vue.js’te Performans İnce Ayarı: Reactivity, computed ve v-memo ile Akıcı Arayüzler
Vue reactivity maliyetlerini azaltma, computed/ watchEffect farkı ve v-memo ile render optimizasyonu.
Vue projeleri büyüdükçe çoğu problem “özellik eksikliği”nden değil, gereksiz yeniden render ve pahalı reactivity zincirlerinden çıkar. Bu yazıda, Vue 3 ile arayüzü daha akıcı hale getirecek pratik performans ayarlarına odaklanıyoruz.
1) Reactivity maliyeti nerede oluşur?
Vue, state değişimlerini izler ve template’i günceller. Sorun; çok sık değişen state’in (örn. arama input’u, slider, websocket akışı) geniş alanları etkilemesiyle ortaya çıkar.
İpucu: Sık değişen veriyi, UI’ın sadece gerekli kısmına “yakın” tutun. Büyük objeleri tek parça reactive yapmak yerine parçalayın.
import { ref, shallowRef } from 'vue'
const query = ref('') // sık değişir
const results = shallowRef([]) // büyük dizi; derin izleme istemiyoruz
shallowRef / shallowReactive: Derin izleme yapmadığı için büyük veri yapılarında (liste, grafik datası, cache) işe yarar.
2) computed: “cache” gibi düşünün
Template içinde fonksiyon çağırmak kolaydır ama her render’da tekrar çalışabilir.
Kötü örnek:
<template>
<li v-for="u in filteredUsers()" :key="u.id">{{ u.name }}</li>
</template>
İyi örnek:
import { computed, ref } from 'vue'
const users = ref([])
const query = ref('')
const filteredUsers = computed(() => {
const q = query.value.toLowerCase().trim()
if (!q) return users.value
return users.value.filter(u => u.name.toLowerCase().includes(q))
})
<template>
<li v-for="u in filteredUsers" :key="u.id">{{ u.name }}</li>
</template>
computed bağımlılıklar değişmedikçe sonucu cache’ler. Büyük listelerde ciddi fark yaratır.
3) watch vs watchEffect: doğru aracı seçin
watch: Hangi kaynağı izlediğin belli, yan etkiler için kontrollüdür.watchEffect: İçeride kullanılan reaktifleri otomatik toplar; hızlı prototip için iyi ama “fazla tetiklenme” riski taşır.
Arama için debounce + watch:
import { ref, watch } from 'vue'
const query = ref('')
const loading = ref(false)
let t
watch(query, (q) => {
clearTimeout(t)
t = setTimeout(async () => {
loading.value = true
// await fetchResults(q)
loading.value = false
}, 250)
})
Bu sayede her tuş vuruşunda API çağırmazsın.
4) v-memo: render’ı “kilitleyin” (Vue 3.2+)
Bir liste öğesi sık değişmeyen verilere bağlıysa, v-memo ile Vue’ya “şunlar değişmedikçe tekrar render etme” diyebilirsin.
<template>
<ul>
<UserRow
v-for="u in users"
:key="u.id"
:user="u"
v-memo="[u.id, u.updatedAt]"
/>
</ul>
</template>
updatedAt değişmedikçe satırın VDOM karşılaştırması bile minimuma iner.
5) Büyük listeler: “virtualization” düşünün
10.000 satırı DOM’a basmak yerine sadece görünen kısmı render edin. Vue ekosisteminde vue-virtual-scroller gibi çözümler var. Mantık basit: görünür alan + buffer.
Minimal yaklaşım:
- Satır yüksekliği sabitse virtualization çok kolay.
- Değişkense ölçüm maliyeti artar; yine de çoğu zaman kazançlıdır.
6) Küçük ama etkili ipuçları
- Template’te pahalı hesaplardan kaçın,
computedkullan. - Büyük immutable verileri
markRawile reactivity dışına al (örn. 3rd party instance’lar). - Bileşenleri gereksizce “prop zinciri” ile güncelleme; gerçekten gerekli prop’ları geçir.
- Chrome Performance + Vue Devtools ile “hangi component kaç kere render olmuş” kontrol et.
Sonuç
Vue zaten hızlı; ama akıcılık, neye reactivity verdiğin ve render’ı nasıl sınırladığın ile belirleniyor. computed ile cache, watch ile kontrollü yan etki, shallowRef ile derin izlemeyi azaltma ve v-memo ile render kilidi; en hızlı kazanım sağlayan dört hamle.