Vue.js ve Modern Web Geliştirme
Modern web uygulamalarının karmaşıklığı, geliştiricileri kodun yeniden kullanılabilirliği, bakım kolaylığı ve ölçeklenebilirliğini merkeze alan mimarilere yöneltmiştir. Bu gereksinimler doğrultusunda, komponent tabanlı mimari (Component-Based Architecture - CBA), geleneksel Model-View-Controller (MVC) yaklaşımına kıyasla daha etkili bir paradigma olarak öne çıkmaktadır. Vue.js, bu paradigmayı benimseyen, progresif ve öğrenme eğrisi nispeten düşük bir JavaScript çerçevesidir.
Vue.js'in temel felsefesi, kullanıcı arayüzünün kendi iç durumunu (state) yönetebilen, bağımsız ve birbirine bağlanabilir komponentlerden oluşmasıdır. Bu yaklaşım, uygulamayı mantıksal ve fonksiyonel bütünlüğü olan küçük parçalara bölerek, geliştirme sürecini yapılandırır. Her komponent, kendine ait HTML şablonu, JavaScript mantığı ve kapsamı belirli CSS stillerini kapsayabilir, bu da güçlü bir kapsülleme (encapsulation) sağlar.
Çerçevenin reaktif veri bağlama sistemi, komponentlerin durumundaki değişikliklerin otomatik olarak görünüme yansıtılmasını sağlar. Bu reaktivite, DOM manipülasyonunun manuel yönetiminden kaynaklanan hataları büyük ölçüde azaltır ve geliştiriciye, uygulamanın iş mantığına odaklanma olanağı tanır. Vue.js, bu özellikleriyle küçük projelerden büyük kurumsal uygulamalara kadar geniş bir yelpazede etkin şekilde kullanılabilir.
Komponent tabanlı geliştirme, geliştirme ekiplerinde iş bölümünü kolaylaştırır. Farklı geliştiriciler, uygulamanın farklı komponentlerini eşzamanlı olarak geliştirebilir, bu da proje sürelerinin kısalmasına katkıda bulunur. Ayrıca, iyi tasarlanmış bir komponent kütüphanesi, farklı projeler arasında tutarlı bir kullanıcı deneyimi sunarken, geliştirme maliyetlerini de düşürür. Vue.js'in esnek ve aşamalı benimsenebilir yapısı, mevcut projelere entegrasyonu nispeten kolaylaştırır.
Komponent Nedir?
Yazılım mühendisliği bağlamında, bir komponent, belirli bir işlevselliği veya kullanıcı arayüzü (UI) parçasını kapsülleyen, bağımsız olarak geliştirilebilen, test edilebilen ve yeniden kullanılabilen bir yazılım modülüdür. Vue.js'de bu kavram, kendi kendine yeten ve tekrar kullanılabilir Vue örnekleri olarak somutlaşır. Her komponent, belirli bir görevi yerine getirmek üzere tasarlanmıştır ve uygulamanın genel durumundan soyutlanmış kendi iç durumunu, yaşam döngüsünü ve davranışını yönetir.
Komponentlerin temel amacı, karmaşıklığı yönetmektir. Monolitik bir yapı yerine, uygulama daha küçük, anlaşılması ve yönetilmesi daha kolay parçalara ayrılır. Örnğin, tipik bir e-ticaret uygulaması, bir ürün listesi komponenti, bir sepet komponenti ve bir kullanıcı profili komponentinden oluşabilir. Bu soyutlama, hata ayıklama, test yazma ve yeni özellikler ekleme süreçlerini büyük ölçüde basitleştirir.
| Kavram | Açıklama | Vue.js'deki Karşılığı |
|---|---|---|
| Kapsülleme (Encapsulation) | İlgili veri, mantık ve görünümün tek bir birimde toplanması. | Tek Dosya Komponenti (.vue uzantılı dosya) |
| Yeniden Kullanılabilirlik (Reusability) | Bir komponentin farklı bağlamlarda ve projelerde defalarca kullanılabilmesi. | Global veya lokal komponent kaydı ve kullanımı. |
| Kompozisyon (Composition) | Basit komponentlerin, daha karmaşık özellikler oluşturmak için bir araya getirilmesi. | Ebeveyn-Çocuk (Parent-Child) komponent hiyerarşisi. |
| Izolasyon (Isolation) | Bir komponentin iç mantığının ve durumunun dış dünyadan korunması. | Komponent kapsamındaki veriler ve `scoped` CSS. |
Vue'da bir komponent, temel olarak bir seçenekler nesnesi (options object) olarak tanımlanır. Bu nesne, komponentin şablonunu (`template`), verisini (`data`), metodlarını (`methods`), izlenen özelliklerini (`computed`) ve yaşam döngüsü kancalarını (`lifecycle hooks`) içerir. Aşağıda, basit bir buton komponentinin en temel tanımı gösterilmektedir. Bu tanım, Vue 3'ün Composition API kullanılarak yapılmıştır ve modern bir yaklaşımı yansıtır.
// Basit bir sayaç butonu komponenti
import { ref } from 'vue';
export default {
name: 'CounterButton',
template: `
<button @click="increment">
Tıklandı: {{ count }} kere
</button>
`,
setup() {
const count = ref(0);
const increment = () => {
count.value++;
};
return { count, increment };
}
};
Bu örnekte, `CounterButton` adlı komponent, kendi iç durumunu (`count`) ve bu durumu değiştiren bir yöntemi (`increment`) yönetir. `@click` direktifi ile butona tıklama olayı dinlenir ve `increment` metodu tetiklenir. Komponentin şablonu, `{{ count }}` sözdizimi ile reaktif bir şekilde durumunu görüntüler. Bu yapı, komponentin davranışının tamamen kendi içinde kapsüllendiğini ve dışarıdan doğrudan müdahale olmadan çalışabildiğini gösterir.
Tek Dosya Komponentleri (SFC)
Vue.js ekosistemindeki en önemli yeniliklerden biri, Tek Dosya Komponenti (Single File Component - SFC) kavramıdır. Bu yaklaşım, bir komponentin şablon (HTML), mantık (JavaScript/TypeScript) ve stil (CSS/SCSS) kodlarını, `.vue` uzantılı tek bir dosya içinde birleştirir. Bu birleştirme, geliştirme deneyimini önemli ölçüde iyileştirirken, komponentin yapısal bütünlüğünü korur. SFC'ler, web uygulamalarının geliştirilmesinde modülerlik ve organize yapıyı teşvik eden bir standart haline gelmiştir.
Bir SFC dosyasının temel yapısı üç ana bölümden oluşur: <template>, <script> ve <style>. <template> bölümü, komponentin HTML yapısını ve Vue direktiflerini tanımlar. <script> bölümü, komponentin davranışını, durumunu ve yaşam döngüsünü kontrol eden JavaScript kodunu içerir. <style> bölümü ise, yalnızca bu komponente özgü stil kurallarını belirler. Bu bölümler, ayrı dosyalarda bulunmak yerine tek bir yerde toplandığı için, geliştiricinin ilgili koda daha hızlı erişmesini ve değişiklik yapmasını sağlar.
SFC'lerin en güçlü yanlarından biri, <style> etiketine `scoped` niteliğinin eklenebilmesidir. Bu nitelik, CSS kurallarının yalnızca tanımlandığı komponentin kapsamı içinde geçerli olmasını sağlar, böylece stil çakışmaları (style collisions) önlenir. Bu mekanizma, Vue'nin derleme aşamasında her komponente benzersiz bir veri özniteliği (data attribute) atayarak ve CSS seçicilerini buna göre değiştirerek çalışır. Bu, büyük ölçekli projelerde stil yönetimini büyük ölçüde kolaylaştırır.
| SFC Bölümü | Zorunluluk | İşlevi | Örnek |
|---|---|---|---|
<template> |
Zorunlu (En az bir kök eleman) | Komponentin görünüm yapısını (DOM) tanımlar. | <div>{{ message }}</div> |
<script> |
Zorunlu (setup veya options API) | Komponentin davranış, veri ve mantığını içerir. | export default { data() { return { message: 'Merhaba' } } } |
<style> |
İsteğe Bağlı | Komponente özgü stil kurallarını tanımlar. | .red { color: crimson; } |
SFC'lerin kullanımı, geliştirme sürecinde build araçlarının (Vite veya Webpack) kullanılmasını gerektirir. Bu araçlar, `.vue` dosyalarını tarayıcının anlayabileceği standart JavaScript modüllerine dönüştüren Vue derleyicisini (Vue Compiler) kullanır. Derleme sırasında, şablonlar optimize edilmiş render fonksiyonlarına çevrilir, <script> bölümü modül sistemine entegre edilir ve <style scoped> bölümü işlenerek kapsamlandırılır. Bu süreç, geliştirme aşamasında sıcak modül değiştirme (Hot Module Replacement - HMR) gibi gelişmiş özelliklerin kullanılmasına olanak tanır.
- Yapısal Netlik: İlgili tüm kod (HTML, JS, CSS) tek bir dosyada bulunur, bu da navigasyonu ve anlaşılırlığı artırır.
- Kapsamlı Stilleme: `scoped`, `module` veya `lang` (Sass, Less) gibi niteliklerle gelişmiş stil yönetimi.
- Ön İşleme Desteği: <script> ve <style> bloklarında TypeScript, JSX, Sass, Less gibi diller direkt kullanılabilir.
- Optimizasyon: Derleyici, şablonları çalışma zamanında daha hızlı çalışan render fonksiyonlarına derleyebilir.
Composition API'nin SFC'lerle birlikte kullanımı, komponent mantığının daha etkili bir şekilde düzenlenmesine olanak tanır. `setup()` fonksiyonu, komponentin reaktif durumunu ve metodlarını oluşturmak için merkezi bir nokta sağlar. Bu fonksiyon içinde, farklı işlevselliklere ait kod, kompozisyon fonksiyonları (composables) kullanılarak mantıksal olarak gruplandırılabilir. Bu yaklaşım, özellikle karmaşık komponentlerde, Options API'ye kıyasla kodun daha iyi organize edilmesini ve yeniden kullanılmasını sağlar. Aşağıda, bir kullanıcı verisi yükleyen komponentin Composition API ile nasıl yapılandırılabileceğine dair basit bir örnek verilmiştir.
<script setup>
import { ref, onMounted } from 'vue'
import { fetchUserData } from './api.js'
// Reaktif durumlar
const user = ref(null)
const isLoading = ref(false)
const error = ref(null)
// Mantıksal işlev: Kullanıcı verisi yükleme
const loadUser = async () => {
isLoading.value = true
error.value = null
try {
user.value = await fetchUserData(1)
} catch (err) {
error.value = err.message
} finally {
isLoading.value = false
}
}
// Yaşam döngüsü kancası
onMounted(() => {
loadUser()
})
</script>
Bu yapı, veri yükleme, durum yönetimi ve hata işleme gibi farklı sorumlulukların birbirinden ayrıldığı, bakımı kolay ve test edilebilir bir komponent oluşturur. SFC formatı, bu tür modern JavaScript modülleri ve API'leri sorunsuz bir şekilde barındırarak, Vue.js ile geliştirilen uygulamaların kalitesini ve sürdürülebilirliğini artırır.
Props ve Veri Akışı
Komponent tabanlı mimaride, birimler arasındaki veri iletişimi kritik öneme sahiptir. Vue.js'de, props (properties), ebeveyn (parent) komponentten çocuk (child) komponente veri aktarmak için kullanılan özel özniteliklerdir. Bu mekanizma, uygulama boyunca tek yönlü bir veri akışı (one-way data flow) sağlar, bu da uygulamanın durumunun tahmin edilebilirliğini ve hata ayıklamanın kolaylığını büyük ölçüde artırır. Props'lar, çocuk komponent tarafından açıkça bildirilmelidir ve ebeveynden gelen veriyi almak için bir arayüz (interface) görevi görür.
Bir prop'un bildirimi, beklenen veri tipini, zorunluluğunu ve hatta varsayılan bir değerini tanımlayabilir. Bu tür doğrulama (validation), geliştirme aşamasında erken hata tespitine yardımcı olur ve komponentin API'sini belgeler. Örneğin, bir `UserProfile` komponenti, `user` adında bir obje prop'u bekleyebilir ve bu prop'un içinde belirli alanların (id, name) bulunmasını şart koşabilir. Props'lar reaktiftir; ebeveyn komponentte prop'un değeri değiştiğinde, bu değişiklik otomatik olarak çocuk komponente iletilir ve görünüm güncellenir.
| Prop Tanımı | Tip | Zorunlu | Varsayılan Değer | Açıklama |
|---|---|---|---|---|
title |
String |
Evet | - | Basit bir metin başlığı. |
count |
Number |
Hayır | 0 |
Sayısal bir değer. |
items |
Array |
Hayır | () => [] |
Bir dizi (array). Varsayılan değer fabrika fonksiyonu olmalıdır. |
config |
Object |
Evet | - | Bir yapılandırma nesnesi. |
onAction |
Function |
Hayır | () => {} |
Bir geri çağırım (callback) fonksiyonu. |
Props'ların salt okunur (read-only) olması, mimarinin temel bir kuralıdır. Bir çocuk komponent, kendisine gelen bir prop'u doğrudan değiştirmemelidir. Bunun yerine, bir değişiklik gerekiyorsa, bu değişikliği ebeveyne bir olay (event) yayınlayarak bildirmelidir. Bu kural, verinin kaynağının (ebeveynin durumu) tek olmasını sağlar ve uygulamanın farklı bölümlerindeki durum senkronizasyonu sorunlarını önler. Veri akışının yönü her zaman açık ve izlenebilir kalır, bu da karmaşık hiyerarşilerde yönetilebilirliği garanti eder.
Props mekanizmasının pratik uygulaması, Composition API'de `defineProps` makrosu ile oldukça basitleştirilmiştir. Bu makro, komponentin aldığı props'ları ve bunların özelliklerini tanımlamak için kullanılır. Aşağıdaki kod örneği, bir `AlertMessage` komponentinin nasıl prop tanımlayabileceğini ve kullanabilecğini göstermektedir. Bu örnekte, `type` prop'u belirli string değerlerini kabul eder ve `message` prop'u zorunludur.
<!-- AlertMessage.vue -->
<template>
<div :class="['alert', `alert-${type}`]" role="alert">
{{ message }}
</div>
</template>
<script setup>
// Props tanımı ve doğrulama
const props = defineProps({
message: {
type: String,
required: true,
validator: (value) => value.length > 0
},
type: {
type: String,
default: 'info',
validator: (value) => ['info', 'success', 'warning', 'danger'].includes(value)
}
})
</script>
<style scoped>
.alert {
padding: 1rem;
border-radius: 0.375rem;
}
</style>
Ebeveyn komponent, bu çocuk komponenti, HTML nitelikleri gibi prop'ları ileterek kullanır. Bu aktarım sırasında, dinamik veriler `v-bind` direktifi (veya kısaltması `:`) kullanılarak bağlanır. Bu yöntem, ebeveynin reaktif durumundaki herhangi bir değişikliğin çocuk komponente anında yansıtılmasını sağlar. Prop'lar aracılığıyla fonksiyonlar da iletilerek, çocuk komponentin ebeveynde tanımlanmış metotları tetiklemesine olanak verilir; bu, iki yönlü iletişimin olay sistemiyle nasıl tamamlandığını gösterir.
Custom Events ve Olay Yönetimi
Tek yönlü veri akışının tamamlayıcı mekanizması, çocuk komponentlerin ebeveynleriyle iletişim kurmasını sağlayan özel olaylar (custom events) sistemidir. Props'lar veriyi aşağıya doğru aktarırken, custom events veriyi ve eylem bildirimlerini yukarıya doğru iletir. Bu model, alt komponentlerin üst komponentin durumunu veya iş mantığını doğrudan değiştirmesini engeller; bunun yerine, bir olayı tetikleyerek (emitting an event) bir değişiklik talebinde bulunmalarını sağlar. Karar verme ve durum güncelleme sorumluluğu, her zaman daha üst seviyedeki, veri sahibi olan komponentte kalır.
Vue.js'de, bir çocuk komponent `$emit` metodunu (Options API) veya `emit` fonksiyonunu (Composition API) kullanarak özel bir olay yayar (emit). Bu olay, bir isme ve isteğe bağlı olarak ek veri yüküne (payload) sahip olabilir. Ebeveyn komponent ise, `v-on` direktifi (veya kısaltması `@`) ile bu olayı dinler ve bir olay işleyicisi (event handler) metodu çalıştırır. Bu metod, genellikle kendi durumunu güncelleyerek veya başka bir işlem başlatarak olaya tepki verir.
Custom events kullanımı, komponentler arasında gevşek bağlı (loosely coupled), bakımı kolay bir ilişki kurar. Alt komponent, üst komponentin nasıl uygulandığından bağımsız olarak, sadece belirli bir eylemin gerçekleştiğini bildirir. Örneğin, bir `SearchBar` komponenti, kullanıcı arama terimini girdiğinde ve butona tıkladığında bir `search` olayı yayar. Bu komponenti kullanan ebeveyn, bu olayı dinleyerek bir API isteği başlatabilir veya yerel bir listeyi filtreleyebilir. Bu ayrım, `SearchBar` komponentinin farklı bağlamlarda, farklı arama mantıklarıyla yeniden kullanılabilmesini sağlar.
Olay yönetiminde dikkat edilmesi gereken önemli bir nokta, olay adlarının kebab-case formatında (küçük harf, tire ile ayrılmış) kullanılmasının önerilmesidir, çünkü bu, HTML niteliklerinin büyük/küçük harfe duyarsız olmasıyla uyumludur. Ayrıca, Composition API'de `defineEmits` makrosu, bir komponentin yayacağı olayları ve bunların beklenen payload yapısını bildirmek için kullanılır. Bu, komponentin API'sini daha açık hale getirir ve geliştirme araçları (Volar) için tip güvenliği sağlar.
<!-- Child Component: TodoItem.vue -->
<template>
<li class="d-flex justify-content-between align-items-center mb-2">
<span :class="{ 'text-decoration-line-through': todo.completed }">
{{ todo.text }}
</span>
<div>
<button @click="emit('toggle', todo.id)" class="btn btn-sm btn-outline-primary me-2">
{{ todo.completed ? 'Geri Al' : 'Tamamla' }}
</button>
<button @click="emit('delete', todo.id)" class="btn btn-sm btn-outline-danger">
Sil
</button>
</div>
</li>
</template>
<script setup>
// Olayların tip güvenliği ile tanımlanması
const emit = defineEmits<{
(e: 'toggle', id: number): void
(e: 'delete', id: number): void
}>()
// Props tanımı
defineProps({
todo: {
type: Object,
required: true
}
})
</script>
Yukarıdaki `TodoItem` komponenti, `toggle` ve `delete` olmak üzere iki özel olay tanımlamıştır. Her iki olay da, ilgili `todo` öğesinin `id`'sini payload olarak ebeveyne iletir. Ebeveyn komponent, bu olayları dinleyerek kendi `todos` dizisini güncelleyebilir. Bu yaklaşım, durum yönetiminin merkezileştirilmesini sağlarken, kullanıcı arayüzü işlemlerinin (butona tıklama) sorumluluğunu alt komponente devreder. Bu model, Flux veya Vuex gibi durum yönetimi kütüphaneleri ile birlikte kullanıldığında daha da güçlü hale gelir.
İleri seviye bir uygulama olarak, `v-model` direktifinin custom events ile nasıl çalıştığını anlamak önemlidir. Bir komponent üzerinde `v-model` kullanmak, aslında `modelValue` adlı bir prop'u ve `update:modelValue` adlı bir olayı dinlemek anlamına gelir. Komponent, iç değeri değiştiğinde `update:modelValue` olayını yayarak, ebeveyn komponentteki veri bağlantısını günceller. Bu, iki yönlü (two-way) veri bağlama benzeri bir senkronizasyon sağlar, ancak arka planda yine de tek yönlü veri akışı ve olay sistemini kullanır. Bu mekanizma, geliştiricilere standart form elemanları gibi davranan, yeniden kullanılabilir ve kontrollü komponentler oluşturma gücü verir.
Slot'lar ve İçerik Dağıtımı
Props ve events, komponentlere veri ve davranış aktarmanın temel yollarıyken, slot'lar (slots) komponentlere içerik (content) dağıtmanın güçlü ve esnek mekanizmasıdır. Bir slot, ebeveyn komponentin, çocuk komponentin şablonunun belirli bir bölümüne kendi içeriğini (HTML, hatta diğer komponentleri) enjekte etmesine olanak tanır. Bu, yüksek düzeyde yeniden kullanılabilir ve adapte edilebilir kapsayıcı (wrapper) komponentler oluşturmanın temelini oluşturur.
En basit haliyle, `
Vue.js, varsayılan slotun yanı sıra, isimli slot'lar (named slots) ve kapsamlı slot'lar (scoped slots) gibi gelişmiş özellikler sunar. İsimli slot'lar, bir komponentin birden fazla içerik giriş noktasına sahip olmasını sağlar. Örneğin, bir `BaseLayout` komponenti `header`, `default` (isimsiz) ve `footer` olmak üzere üç slot tanımlayabilir. Ebeveyn, `v-slot` direktifi (kısaltması `#`) kullanarak içeriğini hangi slota yerleştireceğini belirtebilir. Bu, karmaşık düzen şablonlarının oluşturulmasını mümkün kılar.
- Varsayılan Slot: İsimsiz `
`. Ebeveynin sağladığı tüm içeriği (başka bir slota atanmayan) alır. - İsimli Slot (Named Slot): `
` gibi bir `name` özniteliğine sahiptir. Ebeveynin `v-slot:header` veya `#header` ile sağladığı içeriği alır. - Kapsamlı Slot (Scoped Slot): Çocuk komponentin, slot içeriğine veri iletmesine olanak tanır. Bu, çocuktan ebeveyne bir veri akışı sağlar.
- Dinamik Slot Adı (Dynamic Slot Name): `v-slot:[dynamicSlotName]` sözdizimi ile slot adı dinamik olarak belirlenebilir.
Kapsamlı slot'lar, slot mekanizmasının en güçlü özelliğidir. Bir çocuk komponent, slot etiketinde bir öznitelik olarak veri iletir (örn: `
Aşağıdaki örnek, bir `DataList` komponentinin, veri öğelerini nasıl sağladığını ancak her bir öğenin nasıl render edileceğini ebeveyne nasıl bıraktığını göstermektedir. Bu, komponentin yeniden kullanılabilirliğini maksimuma çıkarır, çünkü aynı veri kaynağı farklı şekillerde (liste, grid, seçici) görüntülenebilir.
<!-- Child Component: DataList.vue -->
<template>
<ul class="list-unstyled">
<li v-for="(item, index) in items" :key="item.id">
<!-- Her öğe için kapsamı bir slot sunuyoruz -->
<slot name="item" :item-data="item" :item-index="index">
<!-- Varsayılan içerik: Ebeveyn bir şey sağlamazsa gösterilir -->
{{ item.name }}
</slot>
</li>
</ul>
</template>
<script setup>
defineProps({
items: {
type: Array,
required: true
}
})
</script>
<!-- Parent Component: ParentComponent.vue -->
<template>
<DataList :items="userList">
<!-- Kapsamlı slot kullanımı -->
<template #item="{ itemData, itemIndex }">
<div class="card mb-3">
<div class="card-body">
<h5 class="card-title">#{{ itemIndex + 1 }} - {{ itemData.fullName }}</h5>
<p class="card-text">Email: {{ itemData.email }}</p>
<button @click="selectUser(itemData)" class="btn btn-primary">Seç</button>
</div>
</div>
</template>
</DataList>
</template>
<script setup>
import DataList from './DataList.vue'
// ... userList reaktif verisi ve selectUser metodu tanımlanır
</script>
Bu yapıda, `DataList` komponenti yalnızca veriyi yineler (`v-for`) ve her yineleme için bir slot bağlamı sağlar. Görsel sunumun tam kontrolü (`card`, `button` ve bunların düzeni) ebeveyn komponente aittir. Bu, inversiyon of control (kontrolün tersine çevrilmesi) ilkesinin mükemmel bir örneğidir ve bileşimsel (compositional) API tasarımının özünü oluşturur. Slot'lar, Vue.js'in komponent sistemini, yalnızca veri değil, aynı zamanda davranış ve görünüm şablonlarını da kapsayacak şekilde genişleterek, geliştiricilere son derece güçlü ve ifade edici bir soyutlama aracı sunar.
Yaşam Döngüsü Hook'ları
Vue komponentleri, oluşturulmasından DOM'a montajına, güncellenmesinden yok edilmesine kadar belirli bir yaşam döngüsünden (lifecycle) geçer. Geliştiricilerin bu döngünün kritik noktalarında kod çalıştırmasına olanak tanıyan özel fonksiyonlar, yaşam döngüsü hook'ları (lifecycle hooks) olarak adlandırılır. Bu hook'lar, komponentin farklı aşamalardaki davranışını hassas bir şeklde kontrol etmek, yan etkileri (side effects) yönetmek ve kaynak sızıntılarını önlemek için vazgeçilmezdir. Options API'de metodlar olarak, Composition API'de ise doğrudan import edilen fonksiyonlar olarak kullanılırlar.
Yaşam döngüsü, temel olarak dört ana fazdan oluşur: Oluşturma (Creation), Montaj (Mounting), Güncelleme (Updating) ve Yok Etme (Destruction). Oluşturma fazında, komponentin reaktif verileri ve olay dinleyicileri hazırlanır, ancak henüz DOM elemanı oluşturulmamıştır. Bu fazdaki `beforeCreate` ve `created` hook'ları, sunucu taraflı render (SSR) veya API istekleri başlatmak gibi DOM erişimi gerektirmeyen kurulum işlemleri için uygundur. `created` hook'unda, `data`, `computed` ve `methods` erişilebilir durumdadır.
Montaj fazı, komponentin DOM'a eklenmesiyle ilgilidir. `beforeMount` hook'u, ilk render işleminden hemen önce çalışır. `mounted` hook'u ise, komponentin DOM elemanının oluşturulup eklendiğinden emin olduğunuz anahtardır. Bu hook, DOM'a bağlı üçüncü taraf kütüphaneleri entegre etmek, DOM elemanlarından ölçüm almak veya sunucudan dinamik veri getirmek için kritik öneme sahiptir. Ancak, `mounted` hook'unun sunucu taraflı render (SSR) sırasında çağrılmadığı unutulmamalıdır.
Bir komponentin reaktif verisi veya aldığı prop'lar değiştiğinde, güncelleme fazı tetiklenir. `beforeUpdate` hook'u, DOM'un yeni veriye göre yeniden render edilmesinden hemen önce çalışır; bu, mevcut DOM durumuna son kez erişmek için kullanışlıdır. `updated` hook'u ise, sanal DOM'un yeniden render edilip gerçek DOM'a yamalandıktan sonra çalışır. Bu hook içinde durumu değiştirmekten kaçınılmalıdır, aksi takdirde sonsuz bir güncelleme döngüsüne neden olabilir. Performans açısından, `updated` hook'unun aşırı kullanımı uygulamayı yavaşlatabilir.
Son olarak, yok etme fazı, bir komponentin DOM'dan kaldırılmadan önceki temizlik aşamasıdır. `beforeUnmount` hook'u, komponent örneği hala tam işlevselken çalışır ve kaynak temizliği için hayati önem taşır. Bu hook içinde, kurulan tüm olay dinleyicileri kaldırılmalı, aktif zamanlayıcılar (setInterval, setTimeout) temizlenmeli ve üçüncü taraf kütüphane örnekleri imha edilmelidir. `unmounted` hook'u ise, komponent tamamen kaldırıldıktan sonra çalışır, ancak bu noktada komponentin artık hiçbir alt elemanı veya etkinliği kalmamıştır.
Composition API'de, bu hook'lar doğrudan `vue` paketinden import edilir ve `setup()` fonksiyonu içinde çağrılır. Bu hook fonksiyonları, bir callback fonksiyonu alır ve bu callback, ilgili yaşam döngüsü anında çalıştırılır. Bu yaklaşım, ilgili kurulum ve temizlik kodlarını mantıksal olarak bir arada gruplamayı kolaylaştırır. Örneğin, bir komponent `mounted` hook'unda bir olay dinleyicisi ekliyorsa, aynı mantıksal bütünlük içinde `unmounted` hook'unda bu dinleyiciyi kaldırmak çok daha nettir.
<script setup>
import { onMounted, onUnmounted, ref, onUpdated } from 'vue'
const count = ref(0)
let externalChartInstance = null
// 1. Montaj Fazı: Üçüncü taraf bir grafik kütüphanesini başlat
onMounted(() => {
console.log('Komponent DOM\'a eklendi.')
// DOM elemanı artık erişilebilir
const canvasEl = document.getElementById('myChart')
externalChartInstance = new ExternalChartLibrary(canvasEl, { /* config */ })
// Global bir olay dinleyicisi ekle
window.addEventListener('resize', handleResize)
})
// 2. Güncelleme Fazı: Veri değiştiğinde grafiği güncelle
onUpdated(() => {
// DİKKAT: Burada count'u değiştirmek sonsuz döngüye sebep olur!
console.log('Komponent güncellendi, yeni count:', count.value)
if (externalChartInstance) {
externalChartInstance.updateData(count.value)
}
})
// 3. Yok Etme Fazı: Kaynakları temizle
onUnmounted(() => {
console.log('Komponent DOM\'dan kaldırılıyor.')
// Olay dinleyicisini kaldır
window.removeEventListener('resize', handleResize)
// Grafik örneğini imha et
if (externalChartInstance) {
externalChartInstance.destroy()
externalChartInstance = null
}
})
function handleResize() {
// Yeniden boyutlandırma işlemi
}
</script>
İleri seviye senaryolarda, `watch` ve `watchEffect` gibi reaktifite API'leri, yaşam döngüsü hook'larına sıklıkla alternatif veya tamamlayıcı olarak kullanılır. Özellikle `watchEffect`, hemen çalışır ve bağımlılıklarını otomatik olarak izleyerek, `mounted` ve `updated` hook'larının bir kombinasyonu gibi davranabilir. Ancak, saf DOM manipülasyonu veya üçüncü taraf kütüphane başlatma gibi yalnızca montaj anında bir kez yapılması gereken işlemler için `onMounted` hook'u kullanımı daha nettir ve daha az yan etki riski taşır. Benzer şekilde, temizlik işlemleri için `watch` ve `watchEffect`'in döndürdüğü temizleme (cleanup) fonksiyonları da kullanılabilir.
Performans optimizasyonu bağlamında, `onActivated` ve `onDeactivated` hook'ları da anlaşılmalıdır. Bu hook'lar, `
Sonuç olarak, yaşam döngüsü hook'ları, Vue komponentlerinin davranışını granüler bir seviyede kontrol etmek için gerekli bir araç setidir. Doğru kullanıldığında, harici kaynakların yönetiminden, veri getirme işlemlerinin zamanlamasına ve performans optimizasyonlarına kadar birçok karmaşık senaryoyu ele almayı mümkün kılar. Geliştiricilerin, hook'ların çalışma sırasını ve her birinin uygun kullanım durumlarını derinlemesine anlaması, sağlam, hatasız ve verimli Vue.js uygulamaları geliştirmenin temel taşıdır. Bu bilgi, komponent tabanlı mimarinin sadece yapı taşlarını oluşturmakla kalmayıp, onların ömür boyu davranışlarını da yönetebilmek anlamına gelir.