Cansu Arı Logo
Blog
Nedir?

v-model’in Gizli Anatomisi - modelValue ve update:modelValue

Vue’nun v-model özelliği sihirli bir direktif gibi görünür ama aslında iki yönlü veri akışını yöneten akıllı bir sözleşmedir.

  • #Vue.js

Skip to content

modelValue ve update:modelValue

Vue’yu öğrenmeye yeni başlayan herkes v-model'i sever. Çünkü bir input’a değer bağlamak kadar kolay bir şey yoktur. Fakat perde arkasında neler döndüğünü anlamadığında, kendi bileşenlerinde v-model çalışmaz ve sihir bozulur. 🙃

Bu yazıda v-model’in nasıl çalıştığını, modelValue ve update:modelValue olaylarının aslında neyi temsil ettiğini adım adım anlatacağız.

Kısaca v-model

En temel haliyle:
<input v-model="name" />
Bu, aslında Vue tarafından şuna çevrilir:
<input :value="name" @input="name = $event.target.value" />
Yani v-model, bir :value binding’i ve bir @input event listener’ının kısayoludur. Ama bu sadece native HTML input’ları için geçerli. Bileşen yazdığında işler değişir. 👇

Bileşenlerde v-model Nasıl Çalışır?

Vue, kendi bileşeninde v-model kullanıldığında otomatik olarak iki şeyi arar:
  1. modelValue adlı bir prop,
  2. update:modelValue adlı bir emit.
<!-- Parent -->
<MyInput v-model="username" />
<!-- MyInput.vue -->
<script setup>
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
</script>
<template>
<input :value="modelValue" @input="emit('update:modelValue', $event.target.value)" />
</template>

Artık v-model tıpkı native input’ta olduğu gibi çift yönlü çalışır: parent değeri gönderir (props), child ise değişikliği bildirir (emit).

İçeride Neler Oluyor?

v-model bir veri akışı protokolüdür. Bu protokolün iki yönü vardır:
  • Downstream (parent → child): modelValue prop’u üzerinden değer akar.
  • Upstream (child → parent): update:modelValue event’iyle değişiklik bildirilir.
Vue bunu şeffaf bir şekilde yönetir. Parent bileşen username değişkenini reactive olarak tutar ve bu değişken, child’daki input değerine otomatik olarak bağlanır.

Yani: v-model, “props içeri, emit dışarı” kuralını iki yönlü hale getirir.

İsimlendirme Değiştirmek Mümkün

Bazı durumlarda birden fazla v-model kullanmak isteyebilirsin (örneğin biri value, biri checked için). Vue buna da izin verir.
<MyToggle v-model:checked="isOn" v-model:label="title" />
<script setup>
const props = defineProps(['checked', 'label'])
const emit = defineEmits(['update:checked', 'update:label'])
</script>
Böylece her v-model farklı bir prop/event çiftiyle eşleşir.

💡 İpucu: Çoklu v-model yapısı, özellikle form bileşenlerinde esneklik sağlar. Örneğin hem “value” hem “valid” state’lerini kontrol etmek için birebir.

v-model’in İçinde Gerçekte Ne Var?

Vue template derleyicisi, v-model gördüğünde bunu otomatik olarak şu pattern’e çevirir:
<MyInput :modelValue="username" @update:modelValue="username = $event" />
Bu sayede senin ekstra bir kod yazmana gerek kalmaz. Ancak kendi bileşeninde defineEmits(['update:modelValue']) yazmadıysan, Vue hata verir: > Missing required emit event: update:modelValue

Bu yüzden v-model’in çalışması tamamen bu sözleşmeye bağlıdır.

İleri Kullanım: Computed v-model

Bazen parent’ta tuttuğun veriyi bileşen içinde biraz dönüştürmek isteyebilirsin. İşte o zaman computed setter/getter ile özel bir v-model yazılabilir:
const message = ref('Hello')
const upper = computed({
get: () => message.value.toUpperCase(),
set: val => message.value = val.toLowerCase()
})
Artık v-model="upper" kullandığında, input her zaman büyük harfli görünür ama küçük harfli kaydedilir. 😎

v-model Modifiers

Vue bazı modifiyer’leri de destekler (.trim, .number, .lazy gibi):
<input v-model.trim.number="age" />
Bunlar aslında input event’ini sarmalayan minik transform fonksiyonlarıdır. Yani v-model.number = parseFloat($event.target.value) gibidir.

.lazy modifiyeri, input yerine change event’ine bağlanır; performans veya doğrulama kontrolü açısından kullanışlıdır.

Birden Fazla v-model Ne Zaman Kullanılır?

Form bileşenlerinde aynı anda birden çok state’i (örneğin value, error, valid) yönetmek için:
<MyField v-model:value="text" v-model:valid="isValid" />
Bu yaklaşım, form doğrulama kütüphanelerinde standart haline gelmiştir. Her biri bağımsız bir veri akışını temsil eder.

Gerçek Hayat Örneği

Basit bir modal bileşeni düşünelim:
<Modal v-model:open="isOpen" />
Child:
<script setup>
const props = defineProps(['open'])
const emit = defineEmits(['update:open'])
function close(){ emit('update:open', false) }
</script>
Artık parent’ta isOpen = false olduğunda modal kapanır, modal içinden kapatıldığında da parent state güncellenir. İki yönlü kontrol tamam.

Yaygın Hatalar

  1. defineEmits(['update:modelValue']) yazmayı unutmak.
  2. v-model yerine hem :modelValue hem @update:modelValue manuel yazmak (gereksizdir).
  3. Props’u doğrudan değiştirmeye çalışmak (props.modelValue = 'x') -- bu Vue’da readonly hatasına neden olur.
  4. v-model kullanırken destructuring ile props’u koparmak (const { modelValue } = props) reaktiviteyi bozar.

Özet Tablo

TerimAnlamı
v-modelİki yönlü binding kısayolu
modelValueParent’tan gelen veri
update:modelValueChild’dan dışarı event
v-model:customÇoklu model desteği
v-model.trimGiriş metnini kırpar
v-model.lazyInput yerine change event’ini dinler

Sonuç

v-model, Vue’nun reaktivite mimarisinde zarif bir veri alışveriş protokolüdür. Bir props ve bir emit çiftinden ibaret gibi görünse de, componentler arası iletişimi kolaylaştıran güçlü bir standarttır.

Kısaca:

  • modelValue → veri içeri
  • update:modelValue → veri dışarı
  • v-model → ikisini otomatik bağlar

Bu mantığı anladığında, artık her bileşeni “form element” gibi çalıştırabilir, karmaşık veri akışlarını zahmetsizce yönetebilirsin.

All tags
  • Vue.js