Vue 3 Composable Yapilari: Yeniden Kullanilabilir Kaliplar ve Mulakat Sorulari 2026

Vue 3 composable yapilarinin ileri duzey kaliplarini, async islemleri, bagimlilik enjeksiyonunu ve 2026 mulakat sorularini kapsayan teknik rehber.

Vue 3 Composables Advanced Patterns

Vue 3'un Composition API'si, frontend gelistirme dunyasinda devrim niteliginde bir degisim yaratti. 2026 yilina gelindiginde composable yapilari artik sadece bir tercih degil, profesyonel Vue projelerinin vazgecilmez bir parcasi haline geldi. Buyuk olcekli uygulamalarda is mantigi paylasimi, durum yonetimi ve yan etki kontrolu gibi konularda composable'lar en etkili cozum olarak kabul goruyor. Bu rehber, ileri duzey composable kaliplarini, gercek dunya senaryolarini ve teknik mulakatlarda siklikla karsilasilan sorulari derinlemesine inceliyor.

Modern Vue ekosisteminde composable'lar, React'taki custom hook'lara benzer bir rol ustleniyor ancak Vue'nun reaktivite sisteminin sunduğu avantajlar sayesinde daha okunakli ve performansli cozumler uretmeye olanak taniyor. Ozellikle TypeScript ile birlikte kullanildiklarinda, tip guvenli ve test edilebilir kod yazmayi kolaylastiriyorlar.

Vue 3 Composable Nedir?

Bir composable, Vue'nun Composition API'sini kullanan ve durum bilgisi iceren (stateful) mantigi kapsulleyen bir fonksiyondur. Konvansiyon olarak use on ekiyle baslar (ornegin useCounter, useFetch) ve reaktif referanslar, computed degerler ve yasam dongusu hook'lari icerebilir. Composable'lar bilesenler arasinda is mantigi paylasimini saglayarak kod tekrarini ortadan kaldirir ve test edilebilirligi onemli olcude arttirir.

Iyi Yapilandirilmis Bir Composable'in Anatomisi

Bir composable tasarlarken dikkat edilmesi gereken bircok kritik nokta bulunuyor. Oncelikle, fonksiyonun tek bir sorumluluk alanina odaklanmasi gerekiyor. SOLID prensiplerinden Single Responsibility ilkesi burada da gecerliligini koruyor. Bir composable hem veri cekme hem form dogrulama hem de animasyon yonetimi yapmamali; bunun yerine her bir sorumluluk icin ayri composable'lar olusturulmali.

Tip guvenligi, profesyonel bir composable'in olmazsa olmazlarindan biri. TypeScript arayuzleri (interface) kullanarak hem giris parametrelerini hem de donus degerlerini acikca tanimlamak, gelistirici deneyimini iyilestiriyor ve hatalarin derleme zamaninda yakalanmasini sagliyor. Asagidaki ornekte, useCounter composable'i bu prensiplerin nasil uygulandigini gosteriyor:

useCounter.tstypescript
import { ref, computed, type Ref } from 'vue'

interface UseCounterOptions {
  min?: number
  max?: number
  initialValue?: number
}

interface UseCounterReturn {
  count: Ref<number>
  doubled: Ref<number>
  increment: () => void
  decrement: () => void
  reset: () => void
}

export function useCounter(options: UseCounterOptions = {}): UseCounterReturn {
  const { min = 0, max = Infinity, initialValue = 0 } = options

  const count = ref(initialValue)
  const doubled = computed(() => count.value * 2)

  function increment() {
    if (count.value < max) count.value++
  }

  function decrement() {
    if (count.value > min) count.value--
  }

  function reset() {
    count.value = initialValue
  }

  return { count, doubled, increment, decrement, reset }
}

Bu ornekte dikkat edilmesi gereken birkac onemli tasarim karari bulunuyor. Ilk olarak, opsiyonel parametreler bir options nesnesi uzerinden aktariliyor; bu yaklasim ileriye donuk uyumlulugu kolaylastiriyor. Ikinci olarak, donus tipi acikca tanimlanmis durumda ve hem reaktif degerler hem de mutasyon fonksiyonlari iceriyor. Ucuncu olarak, min ve max sinirlari sayesinde composable, is kurallarini kendi icinde uyguluyor ve tuketici bilesenlerin bu kontrolu yapmasina gerek kalmiyor.

Hata Yonetimli Asenkron Composable'lar

Gercek uygulamalarda en sik ihtiyac duyulan composable turlerinden biri, asenkron veri cekme islemlerini yoneten yapilardir. Bir API cagrisinin yukleme durumu, hata yonetimi ve iptal mekanizmasi gibi tekrar eden kaliplari tek bir composable icinde toplamak, kod tabanini onemli olcude sadelestiriyor.

Asagidaki useFetchData composable'i, modern JavaScript'in AbortController API'sini kullanarak istek iptalini destekliyor. Bu, ozellikle reaktif URL degisikliklerinde onceki isteklerin otomatik olarak iptal edilmesini saglayarak yaris kosullarini (race conditions) onluyor. Ayrica MaybeRefOrGetter tipi sayesinde hem statik degerler hem de reaktif referanslar parametre olarak kabul ediliyor:

useFetchData.tstypescript
import { ref, watchEffect, onUnmounted, toValue, type Ref, type MaybeRefOrGetter } from 'vue'

interface UseFetchReturn<T> {
  data: Ref<T | null>
  error: Ref<string | null>
  isLoading: Ref<boolean>
  refresh: () => Promise<void>
}

export function useFetchData<T>(
  url: MaybeRefOrGetter<string>
): UseFetchReturn<T> {
  const data = ref<T | null>(null) as Ref<T | null>
  const error = ref<string | null>(null)
  const isLoading = ref(false)
  let abortController: AbortController | null = null

  async function fetchData() {
    // Cancel any in-flight request
    abortController?.abort()
    abortController = new AbortController()

    isLoading.value = true
    error.value = null

    try {
      const response = await fetch(toValue(url), {
        signal: abortController.signal
      })
      if (!response.ok) throw new Error(`HTTP ${response.status}`)
      data.value = await response.json()
    } catch (err) {
      if (err instanceof DOMException && err.name === 'AbortError') return
      error.value = err instanceof Error ? err.message : 'Unknown error'
    } finally {
      isLoading.value = false
    }
  }

  // Re-fetch when URL changes reactively
  watchEffect(() => {
    fetchData()
  })

  onUnmounted(() => abortController?.abort())

  return { data, error, isLoading, refresh: fetchData }
}

Bu composable'in en kritik ozelligi onUnmounted hook'u icerisinde abort islemini gerceklestirmesi. Bilesen DOM'dan kaldirildiginda devam eden istekler otomatik olarak iptal ediliyor ve boylece bellek sizintilari onleniyor. Bu, production ortamlarinda siklikla gozden kacan ancak son derece onemli bir detay.

Composable'lar Icerisinde Yasam Dongusu Hook'lari

Composable'lar icinde onMounted, onUnmounted veya watchEffect gibi yasam dongusu hook'lari kullanilabilir; ancak bu hook'lar yalnizca composable bir bilesen setup() fonksiyonu icerisinde cagrildiginda dogru sekilde calisir. Composable'in setup() bağlami disinda (ornegin bir setTimeout callback'i veya bagimsiz bir utility fonksiyonu icerisinde) cagirilmasi, hook kayitlarinin basarisiz olmasina ve sessiz hatalara yol acar. Bu kurali mulakatlarda vurgulamak, Vue'nun dahili mekanizmalarina olan hakimiyeti gosterir.

Composable Kompozisyonu: Composable'lari Birlestirmek

Composable'larin gercek gucu, birbirleriyle birlestirilebildiklerinde ortaya cikiyor. Kucuk, odakli composable'lar bir araya getirilerek karmasik is mantiklari olusturulabiliyor. Bu yaklasim, Unix felsefesindeki "tek bir isi iyi yap" prensibini Vue ekosisteminde uygulamaya koyuyor.

Asagidaki ornekte, useFetchData ve useDebouncedRef composable'lari birlestirilerek sayfalandirilmis bir arama fonksiyonalitesi olusturuluyor. Bu kalip, e-ticaret urunlerinden kullanici listelerine kadar pek cok senaryo icin yeniden kullanilabilir bir cozum sunuyor:

usePaginatedSearch.tstypescript
import { ref, computed, watch, type Ref } from 'vue'
import { useFetchData } from './useFetchData'
import { useDebouncedRef } from './useDebouncedRef'

interface UsePaginatedSearchReturn<T> {
  query: Ref<string>
  page: Ref<number>
  results: Ref<T[] | null>
  totalPages: Ref<number>
  isLoading: Ref<boolean>
  error: Ref<string | null>
  nextPage: () => void
  prevPage: () => void
}

export function usePaginatedSearch<T>(
  baseUrl: string,
  perPage = 20
): UsePaginatedSearchReturn<T> {
  const query = useDebouncedRef('', 300)
  const page = ref(1)
  const totalPages = ref(1)

  const apiUrl = computed(
    () => `${baseUrl}?q=${encodeURIComponent(query.value)}&page=${page.value}&limit=${perPage}`
  )

  const { data, error, isLoading } = useFetchData<{ items: T[]; total: number }>(apiUrl)

  const results = computed(() => data.value?.items ?? null)

  watch(data, (response) => {
    if (response) {
      totalPages.value = Math.ceil(response.total / perPage)
    }
  })

  // Reset to page 1 when query changes
  watch(query, () => { page.value = 1 })

  function nextPage() {
    if (page.value < totalPages.value) page.value++
  }

  function prevPage() {
    if (page.value > 1) page.value--
  }

  return { query, page, results, totalPages, isLoading, error, nextPage, prevPage }
}

Bu ornekteki en onemli tasarim detayi, arama sorgusu degistiginde sayfanin otomatik olarak 1'e sifirlanmasi. Kullanici yeni bir arama yaptiginda eski sayfalama durumunun korunmasi mantik hatalarina neden olabilir. Ayrica useDebouncedRef kullanimi sayesinde her tuslama yerine yalnizca kullanici yazmayı biraktiktan 300ms sonra API cagrisi tetikleniyor; bu da gereksiz istek sayisini onemli olcude azaltiyor.

Composable kompozisyonunda dikkat edilmesi gereken bir baska nokta da bagimlilik zinciridir. usePaginatedSearch, useFetchData'ya bagimliyken, useFetchData kendi icinde bagimsizdir. Bu tek yonlu bagimlilik yapisi, test edilebilirligi ve bakim kolayligini artiran saglikli bir mimari olusturuyor.

Vue.js / Nuxt.js mülakatlarında başarılı olmaya hazır mısın?

İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.

Provide/Inject ile Bagimlilik Enjeksiyonu

Vue'nun provide/inject mekanizmasi, composable'larla birlestirildiginde guclu bir bagimlilik enjeksiyonu sistemi olusturuyor. Bu kalip ozellikle tema yonetimi, yerellestime veya kullanici oturumu gibi uygulama genelinde paylasilan durumlarin yonetiminde tercih ediliyor. Props drilling (proplari katman katman aktarma) sorununu ortadan kaldirarak bilesen agacinin herhangi bir noktasindan paylasilan duruma erisim sagliyor.

Asagidaki ornekte, tema yonetimi icin provide/inject tabanli bir composable cifti tasarlaniyor. provideTheme fonksiyonu ust bilesen tarafindan cagirilirken, useTheme fonksiyonu alt bilesen agacinin herhangi bir noktasindan tema bilgisine erisim sagliyor:

useTheme.tstypescript
import { provide, inject, ref, readonly, type InjectionKey, type Ref } from 'vue'

type Theme = 'light' | 'dark' | 'system'

interface ThemeContext {
  theme: Readonly<Ref<Theme>>
  setTheme: (t: Theme) => void
  resolvedTheme: Readonly<Ref<'light' | 'dark'>>
}

const ThemeKey: InjectionKey<ThemeContext> = Symbol('theme')

export function provideTheme(initial: Theme = 'system') {
  const theme = ref<Theme>(initial)

  const resolvedTheme = computed<'light' | 'dark'>(() => {
    if (theme.value !== 'system') return theme.value
    return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
  })

  function setTheme(t: Theme) {
    theme.value = t
  }

  const context: ThemeContext = {
    theme: readonly(theme),
    setTheme,
    resolvedTheme: readonly(resolvedTheme)
  }

  provide(ThemeKey, context)
  return context
}

export function useTheme(): ThemeContext {
  const context = inject(ThemeKey)
  if (!context) {
    throw new Error('useTheme() requires a parent component to call provideTheme()')
  }
  return context
}

Bu kaliptaki InjectionKey kullanimi, TypeScript tip cikarimini otomatik olarak sagliyor. inject cagrisi dogru tipi donduruyor ve gelistiriciler ek tip atamasina ihtiyac duymuyor. Ayrica readonly sarmalayicisi, tema degerinin yalnizca setTheme fonksiyonu araciligiyla degistirilebilmesini garantiliyor ve boylece tek yonlu veri akisi prensibi korunuyor.

Bu yaklasimin Pinia veya diger durum yonetimi kutuphanelerine gore avantaji, bilesen agacinin belirli bir dalina ozel durum olusturabilmesidir. Ornegin, bir uygulamanin farkli bolumlerinde farkli tema ayarlari kullanmak mumkun hale geliyor.

Form Dogrulama Composable'i

Form islemleri, frontend uygulamalarinin en karmasik ve hata egilimli alanlarindan biridir. Dogrulama kurallari, hata mesajlari ve form durumu yonetimi gibi tekrarlayan kaliplari bir composable icerisinde soyutlamak, hem kod kalitesini hem de gelistirici verimlilgini artiriyor.

Asagidaki useFormValidation composable'i, generic tipler ve kural tabanli dogrulama yaklasimi kullanarak herhangi bir form yapisi icin uyarlanabilir bir cozum sunuyor. Her alan icin birden fazla dogrulama kurali tanimlanabiliyor ve kurallar sirali olarak calistiriliyor:

useFormValidation.tstypescript
import { reactive, computed, type UnwrapNestedRefs } from 'vue'

type ValidationRule<T> = (value: T) => string | true
type FieldRules<T> = { [K in keyof T]?: ValidationRule<T[K]>[] }

interface UseFormReturn<T extends Record<string, any>> {
  fields: UnwrapNestedRefs<T>
  errors: Record<keyof T, string>
  isValid: Ref<boolean>
  validate: () => boolean
  resetErrors: () => void
}

export function useFormValidation<T extends Record<string, any>>(
  initialValues: T,
  rules: FieldRules<T>
): UseFormReturn<T> {
  const fields = reactive({ ...initialValues }) as UnwrapNestedRefs<T>

  const errors = reactive(
    Object.keys(initialValues).reduce(
      (acc, key) => ({ ...acc, [key]: '' }),
      {} as Record<keyof T, string>
    )
  )

  function validate(): boolean {
    let valid = true
    for (const key of Object.keys(rules) as (keyof T)[]) {
      const fieldRules = rules[key] || []
      errors[key] = '' as any
      for (const rule of fieldRules) {
        const result = rule(fields[key])
        if (result !== true) {
          errors[key] = result as any
          valid = false
          break // Stop at first error per field
        }
      }
    }
    return valid
  }

  function resetErrors() {
    for (const key of Object.keys(errors)) {
      (errors as any)[key] = ''
    }
  }

  const isValid = computed(() =>
    Object.values(errors).every((e) => e === '')
  )

  return { fields, errors, isValid, validate, resetErrors }
}

Bu composable'in tasariminda birkac kritik karar onemlidir. reactive kullanilarak form alanlari derin reaktivite ile sarmalanmis durumda; bu, ic ice gecmis nesne yapilari icin dogru calisan bir cozum sunuyor. Dogrulama fonksiyonu her alan icin ilk hatada duruyor (break ifadesi); bu, kullanici deneyimi acisindan tek seferde tum hatalari gostermek yerine adim adim duzeltmeye yonlendiren bir yaklasim. Ancak projenin gereksinimlerine gore tum hatalari toplamak icin break ifadesi kaldirilabilir.

Composable'larin Test Edilmesi

Composable'lar, Vue bilesenleri disinda calistiklari icin test edilmeleri ilk bakista karmasik gorunebilir. Ancak dogru yaklasimla composable testleri, bilesen testlerinden cok daha basit ve hizli hale geliyor. Anahtar nokta, composable'in bir bilesen baglami icerisinde calistirilmasini saglayan bir yardimci fonksiyon (wrapper) olusturmak.

Asagidaki ornekte, withSetup yardimci fonksiyonu composable'i minimum bir bilesen icerisinde calistirarak reaktivite ve yasam dongusu hook'larinin dogru calismalarini sagliyor:

useCounter.spec.tstypescript
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import { defineComponent, h } from 'vue'
import { useCounter } from './useCounter'

function withSetup<T>(composable: () => T): { result: T; unmount: () => void } {
  let result!: T
  const wrapper = mount(
    defineComponent({
      setup() {
        result = composable()
        return () => h('div')
      }
    })
  )
  return { result, unmount: () => wrapper.unmount() }
}

describe('useCounter', () => {
  it('initializes with default value', () => {
    const { result } = withSetup(() => useCounter())
    expect(result.count.value).toBe(0)
  })

  it('respects min and max boundaries', () => {
    const { result } = withSetup(() =>
      useCounter({ min: 0, max: 3, initialValue: 3 })
    )
    result.increment()
    expect(result.count.value).toBe(3) // Capped at max

    result.count.value = 0
    result.decrement()
    expect(result.count.value).toBe(0) // Capped at min
  })

  it('computes doubled value reactively', () => {
    const { result } = withSetup(() => useCounter({ initialValue: 5 }))
    expect(result.doubled.value).toBe(10)
    result.increment()
    expect(result.doubled.value).toBe(12)
  })
})

Test stratejisi olarak su yaklasim onerilmektedir: her composable icin oncelikle baslangic durumunu dogrulamak, ardindan durum degisikliklerini ve sinir kosullarini test etmek, son olarak da yan etkilerin (API cagirilari, zamanlayicilar vb.) dogru calisldigini kontrol etmek. withSetup yardimci fonksiyonu, projede tum composable testleri icin standart bir kalip olarak kullanilabilir.

Vitest'in vi.useFakeTimers() fonksiyonu, zamanlayici tabanli composable'larin (ornegin debounce veya throttle) deterministik testlerini mumkun kiliyor. Asenkron composable'lar icin ise flushPromises yardimci fonksiyonu kullanilarak Promise cozumlemelerinin tamamlanmasi beklenebiliyor.

Referans Mimari Olarak VueUse

VueUse kutuphanesi, 200'den fazla production-ready composable ile Vue ekosisteminin en kapsamli composable koleksiyonunu sunuyor. useLocalStorage, useDark, useIntersectionObserver gibi yapilar hem projelerinizde dogrudan kullanilabilir hem de kendi composable'larinizi tasarlarken referans mimari gorevi gorur. Mulakat hazirliginda VueUse kaynak kodunu incelemek, ileri duzey composable kaliplarini anlamanin en etkili yollarindan biridir.

Sikca Sorulan Mulakat Sorulari

Vue 3 composable'lari, 2026 yilinda teknik mulakatlarin en onemli konularindan biri olmaya devam ediyor. Asagida siklikla karsilasilan sorular ve beklenen yanitlarin ozeti yer aliyor.

Composable ile mixin arasindaki temel fark nedir? Mixin'ler kaynak birlestirme (merge) yoluyla calisir ve isim catismalarina aciktir; ayrica hangi ozelligin hangi mixin'den geldigini takip etmek zorlasar. Composable'lar ise acik import ve donus degerleri ile calisir, tam tip guvenligi saglar ve bagimlilik zinciri seffaftir.

Bir composable ne zaman ref, ne zaman reactive kullanmali? Genel kural olarak, primitif degerler ve tekil durum parcalari icin ref tercih edilir. Karmasik nesne yapilari ve form durumlari icin reactive daha dogal bir API sunar. Composable'in donus degerlerinde ref kullanimi, destructuring sirasinda reaktivitenin korunmasini garanti eder.

toValue ile unref arasindaki fark nedir? Vue 3.3 ile tanitilan toValue, hem Ref, hem duz deger, hem de getter fonksiyonlarini destekler. unref ise yalnizca Ref ve duz degerleri isler. Modern composable'larda toValue tercih edilmelidir cunku MaybeRefOrGetter tipi ile uyumludur.

Composable icerisinde yan etkiler nasil temizlenir? onUnmounted veya onScopeDispose hook'lari kullanilarak event listener'lar, zamanlayicilar ve devam eden istekler temizlenir. effectScope API'si ise birden fazla reaktif etkiyi gruplayarak toplu temizlik yapmayi mumkun kilar.

Composable'larda yaris kosullari (race conditions) nasil onlenir? Asenkron composable'larda AbortController kullanilarak onceki istekler iptal edilir. Alternatif olarak, bir istek kimlik sistemi (request ID) ile yalnizca en son istegin sonucunun islenmesi saglanabilir.

effectScope ne ise yarar ve ne zaman kullanilir? effectScope, birden fazla watcher ve computed degeri tek bir kapsam altinda gruplayarak toplu durdurma (stop) islemi yapmayi saglar. Ozellikle composable'larin programatik olarak olusturulup yok edildigi senaryolarda bellek yonetimi icin kritik oneme sahiptir.

Sonuc

Vue 3 composable yapilari, modern frontend mimarisinin temel taslarini olusturuyor. Bu rehberde incelenen kaliplar, hem gunluk gelistirme pratiklerinde hem de teknik mulakatlarda basarili olmayi saglayacak kapsamli bir bilgi temeli sunuyor. Ozetlemek gerekirse:

  • Tip guvenligi: TypeScript arayuzleri ile hem giris hem cikis tiplerini acikca tanimlamak, composable'larin guvenilirligini arttirir.
  • Tek sorumluluk: Her composable yalnizca bir is mantigi alanina odaklanmali ve kompozisyon yoluyla birlestirilebilmeli.
  • Yan etki yonetimi: onUnmounted ve onScopeDispose ile temizlik islemlerinin yapilmasi, bellek sizintilarini onler.
  • Reaktif parametreler: MaybeRefOrGetter ve toValue kullanimi, composable'larin esnek kullanimi saglayan modern bir API sunar.
  • Test edilebilirlik: withSetup yardimci fonksiyonu ve Vitest ile composable testleri bilesen testlerinden bagimsiz ve hizli hale gelir.
  • Kompozisyon kaliplari: Kucuk composable'lari birlestirerek karmasik is mantiklari olusturmak, bakimi kolay ve olceklenebilir bir mimari saglar.

Bu kaliplari kendi projelerinizde uygulamak ve VueUse gibi kutuphanelerin kaynak kodunu incelemek, composable konusundaki yetkinligi en ust duzeye tasiyacaktir.

Pratik yapmaya başla!

Mülakat simülatörleri ve teknik testlerle bilgini test et.

Etiketler

#vue
#vue-composables
#composition-api
#interview

Paylaş

İlgili makaleler