# 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. - Published: 2026-05-12 - Updated: 2026-05-12 - Author: SharpSkill - Tags: vue, vue-composables, composition-api, interview - Reading time: 12 min --- 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: ```typescript // useCounter.ts import { ref, computed, type Ref } from 'vue' interface UseCounterOptions { min?: number max?: number initialValue?: number } interface UseCounterReturn { count: Ref doubled: Ref 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: ```typescript // useFetchData.ts import { ref, watchEffect, onUnmounted, toValue, type Ref, type MaybeRefOrGetter } from 'vue' interface UseFetchReturn { data: Ref error: Ref isLoading: Ref refresh: () => Promise } export function useFetchData( url: MaybeRefOrGetter ): UseFetchReturn { const data = ref(null) as Ref const error = ref(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: ```typescript // usePaginatedSearch.ts import { ref, computed, watch, type Ref } from 'vue' import { useFetchData } from './useFetchData' import { useDebouncedRef } from './useDebouncedRef' interface UsePaginatedSearchReturn { query: Ref page: Ref results: Ref totalPages: Ref isLoading: Ref error: Ref nextPage: () => void prevPage: () => void } export function usePaginatedSearch( baseUrl: string, perPage = 20 ): UsePaginatedSearchReturn { 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. ## 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: ```typescript // useTheme.ts import { provide, inject, ref, readonly, type InjectionKey, type Ref } from 'vue' type Theme = 'light' | 'dark' | 'system' interface ThemeContext { theme: Readonly> setTheme: (t: Theme) => void resolvedTheme: Readonly> } const ThemeKey: InjectionKey = Symbol('theme') export function provideTheme(initial: Theme = 'system') { const theme = ref(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: ```typescript // useFormValidation.ts import { reactive, computed, type UnwrapNestedRefs } from 'vue' type ValidationRule = (value: T) => string | true type FieldRules = { [K in keyof T]?: ValidationRule[] } interface UseFormReturn> { fields: UnwrapNestedRefs errors: Record isValid: Ref validate: () => boolean resetErrors: () => void } export function useFormValidation>( initialValues: T, rules: FieldRules ): UseFormReturn { const fields = reactive({ ...initialValues }) as UnwrapNestedRefs const errors = reactive( Object.keys(initialValues).reduce( (acc, key) => ({ ...acc, [key]: '' }), {} as Record ) ) 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: ```typescript // useCounter.spec.ts import { describe, it, expect } from 'vitest' import { mount } from '@vue/test-utils' import { defineComponent, h } from 'vue' import { useCounter } from './useCounter' function withSetup(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. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/tr/blog/vue-nuxt/advanced-vue-3-composables-reusable-patterns