Vue.js mülakat soruları: işi kazandıran 25 temel soru

Vue.js mülakatlarına bu 25 temel soruyla hazırlanın. Reaktiviteden composables'a kadar bir sonraki mülakatta öne çıkmak için anahtar kavramlara hâkim olun.

Kod blokları ve Vue logosu eşliğinde teknik bir Vue.js mülakatının görseli

Vue.js mülakatları framework söz diziminden çok daha fazlasını ölçer. İşe alımcılar reaktivite sisteminin ne kadar iyi anlaşıldığını, kodun Composition API ile nasıl düzenlendiğini ve performans ile mimariye dair gerçek sorunların çözülüp çözülemediğini görmek ister.

Hazırlık önerisi

Her sorunun ayrıntılı bir cevabı ve kod örneği vardır. Teknik mülakatlarda kavramları gerçek bir görüşmedeymiş gibi sesli açıklayarak çalışmak işe yarar.

Temel Vue.js soruları

1. Vue 3'te ref ile reactive arasındaki fark nedir?

Bu soru Vue 3'ün temel yapı taşı olan reaktivite sisteminin anlaşılıp anlaşılmadığını sınar. Ana fark, işlenen veri tiplerinde ve erişim söz diziminde yatar.

ref, primitif değerler (string, number, boolean) için reaktif bir referans oluşturur ve değere script içinden erişmek için .value gerektirir. reactive, nesneler için reaktif bir proxy oluşturur ve özelliklere doğrudan erişime izin verir.

javascript
// ref ile reactive karşılaştırma örneği
import { ref, reactive } from 'vue'

// ref: for primitives
// Requires .value in the script
const count = ref(0)
count.value++ // Access with .value

// reactive: for complex objects
// Direct property access
const user = reactive({
  name: 'Alice',
  age: 25
})
user.age++ // No .value needed

// Warning: reactive loses reactivity if reassigned
// user = { name: 'Bob', age: 30 } // ❌ Breaks reactivity
Object.assign(user, { name: 'Bob', age: 30 }) // ✅ Correct

Genel kural: basit değerler için ref, ilişkili birden fazla özelliği olan yapısal nesneler için reactive kullanılır.

2. Vue 3'ün reaktivite sistemi nasıl çalışır?

Vue 3, reaktif nesneler üzerindeki işlemleri yakalamak için JavaScript Proxy'lerini (ES6) kullanır. Object.defineProperty kullanan Vue 2'nin aksine bu yaklaşım, özellik ekleme ve silme işlemlerini dinamik biçimde algılar.

javascript
// Simplified demonstration of the reactivity principle
// Vue uses Proxies to track dependencies

const handler = {
  // Intercept reading
  get(target, key, receiver) {
    track(target, key) // Register the dependency
    return Reflect.get(target, key, receiver)
  },
  // Intercept writing
  set(target, key, value, receiver) {
    const result = Reflect.set(target, key, value, receiver)
    trigger(target, key) // Trigger updates
    return result
  }
}

// Creating a reactive proxy
const reactiveObject = new Proxy(originalObject, handler)

Proxy'nin avantajları arasında yeni özelliklerin algılanması, Map ve Set desteği ile büyük nesnelerde daha iyi performans yer alır.

3. computed ile watch arasındaki farkı açıkla

computed ile watch, reaktivite yönetiminde farklı ihtiyaçları karşılar.

Computed: başka reaktif verilerden türetilen bir değeri hesaplar. Değerler önbelleğe alınır ve yalnızca bağımlılıklar değiştiğinde yeniden hesaplanır. Veri dönüşümleri için idealdir.

Watch: değişikliklere yanıt olarak yan etkiler çalıştırır. API çağrıları, DOM etkileşimleri veya asenkron işlemler için kullanışlıdır.

javascript
// Computed vs watch comparison
import { ref, computed, watch } from 'vue'

const firstName = ref('John')
const lastName = ref('Doe')

// computed: derived value with cache
// Recalculates only if firstName or lastName changes
const fullName = computed(() => {
  console.log('Computing full name') // Called only once
  return `${firstName.value} ${lastName.value}`
})

// Multiple accesses = single execution (cached)
console.log(fullName.value) // "John Doe"
console.log(fullName.value) // No recalculation

// watch: side effect without cache
// Executed on every change
watch(firstName, async (newName, oldName) => {
  // Side effect: API call
  await saveToServer({ firstName: newName })
  console.log(`Name changed from ${oldName} to ${newName}`)
})

4. Virtual DOM nedir ve Vue onu nasıl kullanır?

Virtual DOM, gerçek DOM'un JavaScript üzerindeki hafif bir temsilidir. Vue, bellekte sanal bir ağaç tutar; önceki ve yeni durum arasındaki farkları (diffing) hesaplayarak gerçek DOM'a yalnızca gerekli değişiklikleri uygular.

javascript
// Conceptual representation of the Virtual DOM
// Vue creates this structure internally

const vnode = {
  type: 'div',
  props: {
    class: 'container',
    id: 'app'
  },
  children: [
    {
      type: 'h1',
      props: {},
      children: 'Title'
    },
    {
      type: 'p',
      props: {},
      children: 'Paragraph content'
    }
  ]
}

// When changes occur, Vue compares vnodes
// and updates only the modified elements

Vue 3'ün optimizasyonları arasında statik düğümlerin yukarı taşınması (hoisting), değişiklik tipini belirlemek için patch flag'leri ve derleyicide tree-shaking sayılabilir.

5. Doğrudan ilişkisi olmayan bileşenler arasında iletişim nasıl yönetilir?

Doğrudan ebeveyn-çocuk ilişkisi olmayan bileşenleri haberleştirmek için birkaç desen vardır.

javascript
// Solution 1: Event Bus (small applications)
// eventBus.js
import { ref } from 'vue'

const bus = ref(new Map())

export function useEventBus() {
  // Emit an event
  const emit = (event, payload) => {
    const callbacks = bus.value.get(event) || []
    callbacks.forEach(cb => cb(payload))
  }

  // Listen to an event
  const on = (event, callback) => {
    if (!bus.value.has(event)) {
      bus.value.set(event, [])
    }
    bus.value.get(event).push(callback)
  }

  return { emit, on }
}
javascript
// Solution 2: Provide/Inject for nested components
// Ancestor
import { provide, ref } from 'vue'

const sharedState = ref('shared value')
provide('stateKey', sharedState)

// Descendant (any level)
import { inject } from 'vue'

const state = inject('stateKey')

Daha karmaşık uygulamalar için global durum yönetiminde önerilen çözüm Pinia'dır.

Composition API soruları

6. Composition API'nin Options API'ye göre avantajları nelerdir?

Composition API, klasik Options API'ye kıyasla yapısal birkaç avantaj sunar.

Özellik bazlı düzen: aynı özelliğe ait kod bir arada bulunur; Options API ise tip bazlı (data, methods, computed) ayrım yapar.

Composables ile yeniden kullanım: mantığın yeniden kullanılabilir fonksiyonlara ayrılması kolaydır.

Gelişmiş TypeScript desteği: dekoratörlere gerek kalmadan doğal tip çıkarımı.

javascript
// Options API: code fragmented by type
export default {
  data() {
    return {
      searchQuery: '',
      results: []
    }
  },
  computed: {
    hasResults() {
      return this.results.length > 0
    }
  },
  methods: {
    async search() {
      this.results = await fetchResults(this.searchQuery)
    }
  },
  watch: {
    searchQuery: 'search'
  }
}

// Composition API: code grouped by feature
import { ref, computed, watch } from 'vue'

export function useSearch() {
  const searchQuery = ref('')
  const results = ref([])

  const hasResults = computed(() => results.value.length > 0)

  const search = async () => {
    results.value = await fetchResults(searchQuery.value)
  }

  watch(searchQuery, search)

  return { searchQuery, results, hasResults, search }
}

7. Yeniden kullanılabilir bir composable nasıl yazılır?

Composables, reaktif mantığı kapsülleyen fonksiyonlardır. Yaygın kurallar şunlardır: use ön eki, durum ve metotlar içeren bir nesne döndürmek ve cleanup işlemini yönetmek.

composables/useLocalStorage.jsjavascript
import { ref, watch } from 'vue'

// Composable to synchronize state with localStorage
export function useLocalStorage(key, defaultValue) {
  // Retrieve initial value from localStorage
  const storedValue = localStorage.getItem(key)
  const data = ref(
    storedValue ? JSON.parse(storedValue) : defaultValue
  )

  // Synchronize changes to localStorage
  watch(
    data,
    (newValue) => {
      if (newValue === null) {
        localStorage.removeItem(key)
      } else {
        localStorage.setItem(key, JSON.stringify(newValue))
      }
    },
    { deep: true } // Observe nested objects
  )

  return data
}

// Usage in a component
const theme = useLocalStorage('theme', 'light')
const userPrefs = useLocalStorage('prefs', { notifications: true })
Adlandırma kuralı

Composables, yeniden kullanılabilir doğalarını belirtmek için useXxx kuralını izler. Bu kural okunabilirliği artırır ve reaktif bağımlılıkların tanımlanmasını kolaylaştırır.

8. watchEffect ile watch'u açıkla

watchEffect ve watch her ikisi de değişikliklere tepki verir, ancak yaklaşımları farklıdır.

watchEffect: hemen çalışır ve reaktif bağımlılıkları her değiştiğinde otomatik olarak yeniden yürütülür. Bağımlılıklar otomatik takip edilir.

watch: belirli kaynakları izler, eski ve yeni değerleri sağlar. Tetiklenme zamanı üzerinde daha fazla kontrol verir.

javascript
// watchEffect vs watch comparison
import { ref, watch, watchEffect } from 'vue'

const userId = ref(1)
const userData = ref(null)

// watchEffect: automatic tracking
// Runs immediately
watchEffect(async () => {
  // userId is automatically tracked
  const response = await fetch(`/api/users/${userId.value}`)
  userData.value = await response.json()
})

// watch: explicit sources with old values
watch(userId, async (newId, oldId) => {
  console.log(`User changed from ${oldId} to ${newId}`)
  const response = await fetch(`/api/users/${newId}`)
  userData.value = await response.json()
}, {
  immediate: true // Run immediately like watchEffect
})

// watchEffect with cleanup
watchEffect((onCleanup) => {
  const controller = new AbortController()

  fetch(`/api/users/${userId.value}`, {
    signal: controller.signal
  }).then(/* ... */)

  // Cleanup: cancel previous request
  onCleanup(() => controller.abort())
})

9. script setup içinde TypeScript ile props nasıl yönetilir?

<script setup> söz dizimi, defineProps ve withDefaults ile yerel TypeScript entegrasyonu sağlar.

TypedComponent.vuetypescript
<script setup lang="ts">
// Interface for props
interface Props {
  title: string
  count?: number
  items?: string[]
  onSubmit?: (data: FormData) => void
}

// defineProps with generic typing
// withDefaults for default values
const props = withDefaults(defineProps<Props>(), {
  count: 0,
  items: () => [], // Factory for objects/arrays
  onSubmit: undefined
})

// Props are automatically typed
console.log(props.title) // string
console.log(props.count) // number

// defineEmits with typing
const emit = defineEmits<{
  (e: 'update', value: number): void
  (e: 'delete', id: string): void
}>()

// Typed emit usage
const handleUpdate = () => {
  emit('update', props.count + 1)
}
</script>

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.

Performans soruları

10. Hangi performans optimizasyon teknikleri vardır?

Vue 3, performansı iyileştirmek için birçok mekanizma sunar.

1. v-once: single render for static contentjavascript
<template>
  <div v-once>
    <!-- This content will never be re-rendered -->
    <ComplexStaticComponent />
  </div>
</template>

// 2. v-memo: conditional memoization
<template>
  <div v-for="item in list" :key="item.id" v-memo="[item.id, item.selected]">
    <!-- Re-renders only if id or selected changes -->
    {{ item.name }}
  </div>
</template>

// 3. shallowRef/shallowReactive: shallow reactivity
import { shallowRef, triggerRef } from 'vue'

// Only tracks ref replacement, not internal mutations
const largeList = shallowRef([/* thousands of elements */])

// Force update after mutation
largeList.value.push(newItem)
triggerRef(largeList) // Manually trigger re-render
4. Async components for code-splittingjavascript
import { defineAsyncComponent } from 'vue'

const HeavyComponent = defineAsyncComponent({
  loader: () => import('./HeavyComponent.vue'),
  loadingComponent: LoadingSpinner,
  delay: 200, // Delay before showing loading
  errorComponent: ErrorDisplay,
  timeout: 3000
})

// 5. KeepAlive for component caching
<template>
  <KeepAlive :include="['Dashboard', 'UserProfile']" :max="10">
    <component :is="currentView" />
  </KeepAlive>
</template>

11. Gereksiz yeniden render'lar nasıl önlenir?

Gereksiz render'lar performansı düşürür. Birçok strateji bunları en aza indirmeye yardımcı olur.

javascript
// Problem: function created on each render
<template>
  <!--New function on every render -->
  <ChildComponent @click="() => handleClick(item.id)" />
</template>

// Solution: use a method or ref
<script setup>
const handleItemClick = (id) => {
  // Processing logic
}
</script>

<template>
  <!--Stable reference -->
  <ChildComponent @click="handleItemClick(item.id)" />
</template>
javascript
// Using computed for expensive calculations
import { computed } from 'vue'

// ❌ Recalculated on every render
const getFilteredItems = () => {
  return items.value.filter(/* complex logic */)
}

// ✅ Cached, recalculated only if items changes
const filteredItems = computed(() => {
  return items.value.filter(/* complex logic */)
})

12. Bileşen ve route'ların lazy loading'ini açıkla

Lazy loading, kodu talep üzerine yükleyerek başlangıçtaki bundle boyutunu azaltır.

router/index.jsjavascript
import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: '/',
      // Immediate loading (main bundle)
      component: () => import('@/views/Home.vue')
    },
    {
      path: '/dashboard',
      // Separate chunk with custom name
      component: () => import(
        /* webpackChunkName: "dashboard" */
        '@/views/Dashboard.vue'
      ),
      // Lazy loading child routes
      children: [
        {
          path: 'analytics',
          component: () => import('@/views/Analytics.vue')
        }
      ]
    },
    {
      path: '/admin',
      // Prefetch on link hover
      component: () => import('@/views/Admin.vue'),
      meta: { prefetch: true }
    }
  ]
})

export default router

Vue Router soruları

13. Route'lar guard'lar ile nasıl korunur?

Navigation guard'lar route erişimini kontrol etmeye yarar.

router/index.jsjavascript
import { createRouter } from 'vue-router'
import { useAuthStore } from '@/stores/auth'

const router = createRouter({
  routes: [
    {
      path: '/dashboard',
      component: Dashboard,
      meta: { requiresAuth: true, roles: ['admin', 'user'] }
    }
  ]
})

// Global guard: checks authentication
router.beforeEach(async (to, from, next) => {
  const auth = useAuthStore()

  // Public route
  if (!to.meta.requiresAuth) {
    return next()
  }

  // Check authentication
  if (!auth.isAuthenticated) {
    return next({
      path: '/login',
      query: { redirect: to.fullPath }
    })
  }

  // Check roles if specified
  if (to.meta.roles && !to.meta.roles.includes(auth.user.role)) {
    return next('/unauthorized')
  }

  next()
})

// Component-level guard
export default {
  beforeRouteEnter(to, from, next) {
    // No access to this here
    next(vm => {
      // Access component instance via vm
      vm.loadData()
    })
  },
  beforeRouteLeave(to, from, next) {
    // Confirm before leaving if form modified
    if (this.hasUnsavedChanges) {
      const answer = confirm('Leave without saving?')
      next(answer)
    } else {
      next()
    }
  }
}

14. Route'lara props nasıl iletilir?

Vue Router, bileşenlerin route parametrelerinden ayrıştırılmasına olanak tanır.

javascript
// Route configuration with props
const routes = [
  {
    path: '/user/:id',
    component: UserProfile,
    // Boolean mode: passes params as props
    props: true
  },
  {
    path: '/search',
    component: SearchResults,
    // Function mode: custom transformation
    props: (route) => ({
      query: route.query.q,
      page: parseInt(route.query.page) || 1,
      filters: route.query.filters?.split(',') || []
    })
  },
  {
    path: '/static',
    component: StaticPage,
    // Object mode: static props
    props: { sidebar: true, theme: 'dark' }
  }
]
UserProfile.vuejavascript
<script setup>
// Props are automatically injected
defineProps<{
  id: string
}>()
</script>

// SearchResults.vue
<script setup>
defineProps<{
  query: string
  page: number
  filters: string[]
}>()
</script>

Pinia ve durum yönetimi soruları

15. Pinia ile Vuex arasındaki farklar nelerdir?

Pinia, Vue 3 için resmi durum yöneticisidir ve Vuex'i sadeleştirilmiş bir API ile değiştirir.

| Özellik | Vuex | Pinia | |---------|------|-------| | Mutation'lar | Zorunlu | Gerekmez | | Modüller | Karmaşık konfigürasyon | Bağımsız store'lar | | TypeScript | Sınırlı destek | Yerel ve eksiksiz | | API | Options | Composition + Options | | DevTools | Destekli | Tam destek |

javascript
// Pinia Store with Composition API
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'

export const useCartStore = defineStore('cart', () => {
  // State
  const items = ref([])
  const discountCode = ref(null)

  // Getters (computed)
  const totalItems = computed(() =>
    items.value.reduce((sum, item) => sum + item.quantity, 0)
  )

  const totalPrice = computed(() => {
    const subtotal = items.value.reduce(
      (sum, item) => sum + item.price * item.quantity, 0
    )
    return discountCode.value ? subtotal * 0.9 : subtotal
  })

  // Actions (direct functions)
  function addItem(product) {
    const existing = items.value.find(i => i.id === product.id)
    if (existing) {
      existing.quantity++
    } else {
      items.value.push({ ...product, quantity: 1 })
    }
  }

  function removeItem(productId) {
    const index = items.value.findIndex(i => i.id === productId)
    if (index > -1) {
      items.value.splice(index, 1)
    }
  }

  async function checkout() {
    const response = await api.createOrder(items.value)
    items.value = []
    return response
  }

  return {
    items, discountCode,
    totalItems, totalPrice,
    addItem, removeItem, checkout
  }
})

16. Pinia store durumu nasıl kalıcı kılınır?

Kalıcılık, kullanıcı oturumları arasında durumun korunmasını sağlar.

plugins/piniaPersistedState.jsjavascript
import { watch } from 'vue'

export function createPersistedState(options = {}) {
  const {
    key = 'pinia',
    storage = localStorage,
    paths = null
  } = options

  return ({ store }) => {
    // Restore state on startup
    const savedState = storage.getItem(`${key}-${store.$id}`)
    if (savedState) {
      store.$patch(JSON.parse(savedState))
    }

    // Persist changes
    watch(
      () => store.$state,
      (state) => {
        const toSave = paths
          ? paths.reduce((acc, path) => {
              acc[path] = state[path]
              return acc
            }, {})
          : state

        storage.setItem(
          `${key}-${store.$id}`,
          JSON.stringify(toSave)
        )
      },
      { deep: true }
    )
  }
}

// main.js
import { createPinia } from 'pinia'
import { createPersistedState } from './plugins/piniaPersistedState'

const pinia = createPinia()
pinia.use(createPersistedState({
  key: 'app-state',
  paths: ['user', 'preferences'] // Persist only these keys
}))
Hassas veriler

Hassas verilerin (token'lar, parolalar) localStorage'da saklanmaması iyi bir uygulamadır. Kimlik doğrulama token'ları için httpOnly çerezler daha güvenlidir.

İleri seviye sorular

17. Vue'da plugin sistemi nasıl tasarlanır?

Plugin'ler Vue'yu global özelliklerle genişletmeyi sağlar.

plugins/analyticsPlugin.jsjavascript
export const AnalyticsPlugin = {
  install(app, options = {}) {
    const { trackingId, debug = false } = options

    // Global injection available in all components
    const analytics = {
      trackEvent(category, action, label) {
        if (debug) {
          console.log('Analytics:', { category, action, label })
        }
        // Logic to send to analytics service
        window.gtag?.('event', action, {
          event_category: category,
          event_label: label
        })
      },
      trackPage(path) {
        window.gtag?.('config', trackingId, { page_path: path })
      }
    }

    // Make available via inject
    app.provide('analytics', analytics)

    // Add global property (discouraged in Composition API)
    app.config.globalProperties.$analytics = analytics

    // Custom directive for click tracking
    app.directive('track', {
      mounted(el, binding) {
        el.addEventListener('click', () => {
          analytics.trackEvent('click', binding.value, el.textContent)
        })
      }
    })

    // Automatic route change tracking
    app.mixin({
      mounted() {
        if (this.$route) {
          analytics.trackPage(this.$route.path)
        }
      }
    })
  }
}

// main.js
import { AnalyticsPlugin } from './plugins/analyticsPlugin'

app.use(AnalyticsPlugin, {
  trackingId: 'UA-XXXXX-X',
  debug: import.meta.env.DEV
})

18. Render fonksiyonlarını ve kullanım amacını açıkla

Render fonksiyonları, render üzerinde tam kontrol sunar; oldukça dinamik bileşenler için elverişlidir.

components/DynamicHeading.jsjavascript
import { h } from 'vue'

// Functional component with render function
export const DynamicHeading = {
  props: {
    level: {
      type: Number,
      default: 1,
      validator: (v) => v >= 1 && v <= 6
    }
  },
  setup(props, { slots }) {
    // h() creates a vnode
    // Arguments: type, props, children
    return () => h(
      `h${props.level}`,
      { class: 'dynamic-heading' },
      slots.default?.()
    )
  }
}

// Component with complex conditional logic
export const ConditionalWrapper = {
  props: ['condition', 'wrapper'],
  setup(props, { slots }) {
    return () => {
      if (props.condition) {
        return h(props.wrapper, null, slots.default?.())
      }
      return slots.default?.()
    }
  }
}

// Usage
<DynamicHeading :level="2">Level 2 Title</DynamicHeading>

<ConditionalWrapper :condition="isLink" wrapper="a">
  Conditional content
</ConditionalWrapper>

19. Vue bileşenleri Vitest ile nasıl test edilir?

Birim testleri, bileşenlerin izole davranışını doğrular.

components/__tests__/Counter.spec.jsjavascript
import { describe, it, expect, vi } from 'vitest'
import { mount } from '@vue/test-utils'
import Counter from '../Counter.vue'

describe('Counter', () => {
  it('displays the initial value', () => {
    const wrapper = mount(Counter, {
      props: { initialValue: 5 }
    })

    expect(wrapper.text()).toContain('5')
  })

  it('increments the value on click', async () => {
    const wrapper = mount(Counter)

    await wrapper.find('button.increment').trigger('click')

    expect(wrapper.text()).toContain('1')
  })

  it('emits an event when changed', async () => {
    const wrapper = mount(Counter)

    await wrapper.find('button.increment').trigger('click')

    expect(wrapper.emitted('change')).toBeTruthy()
    expect(wrapper.emitted('change')[0]).toEqual([1])
  })

  it('calls the service on submit', async () => {
    const mockSubmit = vi.fn()
    const wrapper = mount(Counter, {
      global: {
        provide: {
          submitService: mockSubmit
        }
      }
    })

    await wrapper.find('form').trigger('submit')

    expect(mockSubmit).toHaveBeenCalled()
  })
})

20. Vue'da hatalar global olarak nasıl ele alınır?

Vue 3, hataları yakalamak ve yönetmek için birden fazla mekanizma sunar.

main.jsjavascript
import { createApp } from 'vue'

const app = createApp(App)

// Global handler for component errors
app.config.errorHandler = (err, instance, info) => {
  // err: the error
  // instance: the component instance
  // info: string describing where the error occurred

  console.error('Vue error:', err)
  console.error('Component:', instance?.$options?.name)
  console.error('Info:', info)

  // Send to monitoring service
  errorTracker.captureException(err, {
    component: instance?.$options?.name,
    info
  })
}

// Handler for warnings (dev only)
app.config.warnHandler = (msg, instance, trace) => {
  console.warn('Vue warning:', msg)
}
javascript
// ErrorBoundary component
<script setup>
import { onErrorCaptured, ref } from 'vue'

const error = ref(null)

// Captures errors from child components
onErrorCaptured((err, instance, info) => {
  error.value = {
    message: err.message,
    component: instance?.$options?.name,
    info
  }

  // Return false to stop propagation
  return false
})

const retry = () => {
  error.value = null
}
</script>

<template>
  <div v-if="error" class="error-boundary">
    <h2>An error occurred</h2>
    <p>{{ error.message }}</p>
    <button @click="retry">Retry</button>
  </div>
  <slot v-else />
</template>

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.

En iyi uygulamalarla ilgili sorular

21. Vue'da hangi adlandırma kuralları izlenmeli?

Adlandırma kuralları kodun okunabilirliğini ve sürdürülebilirliğini artırır.

javascript
// Component naming
// PascalCase for files and names
// BaseButton.vue, AppHeader.vue, TheNavbar.vue

// Props: camelCase in JS, kebab-case in template
defineProps<{
  userName: string        // JS
  isActive: boolean       // JS
}>()

// <UserCard :user-name="name" :is-active="active" />

// Events: camelCase with action prefix
const emit = defineEmits<{
  (e: 'updateValue', value: string): void  // ✅
  (e: 'submit'): void                       // ✅
  (e: 'value-updated'): void               // ❌ Avoid
}>()

// Composables: use prefix
// useAuth.js, useFetch.js, useLocalStorage.js

// Pinia stores: use prefix + Store suffix
// useUserStore, useCartStore, useSettingsStore

// Constants: SCREAMING_SNAKE_CASE
const MAX_RETRY_COUNT = 3
const API_BASE_URL = '/api/v1'

22. Büyük ölçekli bir Vue projesi nasıl yapılandırılır?

Modüler bir yapı gezintiyi ve bakımı kolaylaştırır.

text
src/
├── assets/              # Static files
├── components/
│   ├── ui/              # Generic components (Button, Modal)
│   └── common/          # Reusable business components
├── composables/         # Reusable logic
│   ├── useAuth.js
│   └── useFetch.js
├── layouts/             # Page layouts
│   ├── DefaultLayout.vue
│   └── AuthLayout.vue
├── modules/             # Functional modules
│   ├── auth/
│   │   ├── components/
│   │   ├── composables/
│   │   ├── stores/
│   │   └── views/
│   └── dashboard/
├── plugins/             # Vue plugins
├── router/
│   ├── index.js
│   └── guards.js
├── stores/              # Global Pinia stores
├── types/               # TypeScript types
├── utils/               # Pure utilities
└── views/               # Pages/Routes

23. v-if ile v-show ne zaman tercih edilir?

v-if ile v-show arasındaki tercih, geçişlerin sıklığına bağlıdır.

javascript
// v-if: low initial cost, expensive toggle
// Removes/adds element from DOM
// Ideal for: rarely modified conditions

<template>
  <!-- v-if: component not created if not admin -->
  <AdminPanel v-if="user.isAdmin" />

  <!-- v-if with v-else-if for multiple conditions -->
  <LoadingSpinner v-if="isLoading" />
  <ErrorMessage v-else-if="error" :message="error" />
  <DataDisplay v-else :data="data" />
</template>

// v-show: higher initial cost, fast toggle
// Uses display: none
// Ideal for: frequent toggles

<template>
  <!-- v-show: always rendered, frequent toggle -->
  <Tooltip v-show="isHovered">
    Contextual information
  </Tooltip>

  <!-- Accordion menu with frequent toggle -->
  <div v-show="isExpanded" class="accordion-content">
    {{ content }}
  </div>
</template>

24. v-for ile listeler nasıl optimize edilir?

Çok sayıda öğenin olduğu durumlarda liste optimizasyonu kritik öneme sahiptir.

javascript
// Always use :key with a unique stable identifier
<template>
  <!--Unique and stable key -->
  <li v-for="item in items" :key="item.id">
    {{ item.name }}
  </li>

  <!--Index as key (reordering issues) -->
  <li v-for="(item, index) in items" :key="index">
    {{ item.name }}
  </li>
</template>

// Filtering and sorting: use computed
<script setup>
import { computed } from 'vue'

const sortedAndFilteredItems = computed(() => {
  return items.value
    .filter(item => item.isActive)
    .sort((a, b) => a.name.localeCompare(b.name))
})
</script>

// Virtualization for very long lists
<script setup>
import { useVirtualList } from '@vueuse/core'

const { list, containerProps, wrapperProps } = useVirtualList(
  largeList,
  { itemHeight: 50 }
)
</script>

<template>
  <div v-bind="containerProps" style="height: 400px; overflow: auto">
    <div v-bind="wrapperProps">
      <div v-for="item in list" :key="item.data.id">
        {{ item.data.name }}
      </div>
    </div>
  </div>
</template>

25. Renderless component desenini açıkla

Renderless bileşenler, HTML yapısını dayatmadan mantığı kapsüller.

components/MouseTracker.vuejavascript
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'

const x = ref(0)
const y = ref(0)

const updatePosition = (event) => {
  x.value = event.clientX
  y.value = event.clientY
}

onMounted(() => {
  window.addEventListener('mousemove', updatePosition)
})

onUnmounted(() => {
  window.removeEventListener('mousemove', updatePosition)
})

// Expose state via slot
defineExpose({ x, y })
</script>

<template>
  <!-- Slot with props: parent decides the rendering -->
  <slot :x="x" :y="y" />
</template>
javascript
// Usage: full control over rendering
<template>
  <MouseTracker v-slot="{ x, y }">
    <div class="cursor-display">
      Position: {{ x }}, {{ y }}
    </div>
  </MouseTracker>

  <MouseTracker v-slot="{ x, y }">
    <svg>
      <circle :cx="x" :cy="y" r="10" fill="red" />
    </svg>
  </MouseTracker>
</template>

Bu desen mantığı sunumdan tamamen ayırır ve yeniden kullanımı en üst düzeye çıkarır.

Sonuç

Bu 25 soru, Vue.js mülakatlarında değerlendirilen temel kavramları kapsar:

  • Reaktivite: ref, reactive, computed, watch
  • Composition API: composables, script setup, TypeScript
  • Performans: lazy loading, sanallaştırma, optimizasyonlar
  • Vue Router: guard'lar, props, gezinme
  • Pinia: store'lar, kalıcılık, asenkron action'lar
  • En iyi uygulamalar: yapı, kurallar, ileri desenler

Etkili bir hazırlık, teorik kavrayışı kod pratiğiyle birleştirir. Burada ele alınan her kavram, mülakat sırasında derinlemesine takip sorularına konu olabilir.

Pratik yapmaya başla!

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

Etiketler

#vue.js
#interview
#frontend
#javascript
#technical questions

Paylaş

İlgili makaleler