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.

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.
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.
// 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 }) // ✅ CorrectGenel 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.
// 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.
// 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.
// 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 elementsVue 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.
// 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 }
}// 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ı.
// 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.
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 })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.
// 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.
<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.
<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-renderimport { 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.
// 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>// 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.
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 routerVue Router soruları
13. Route'lar guard'lar ile nasıl korunur?
Navigation guard'lar route erişimini kontrol etmeye yarar.
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.
// 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' }
}
]<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 |
// 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.
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 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.
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.
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.
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.
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)
}// 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.
// 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.
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/Routes23. 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.
// 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.
// 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.
<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>// 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
Paylaş
İlgili makaleler

Vue 3 Composition API: Reaktivite ve Kompozisyon Rehberi
Vue 3 Composition API konusunda kapsamli rehber. ref, reactive, computed, watch ve composables kullanarak performansli Vue uygulamalari gelistirmek icin gereken her sey.

Nuxt 3: SSR ve statik üretim, eksiksiz rehber
Nuxt 3 ile SSR ve statik üretimi tüm yönleriyle öğrenin. useFetch'ten route rules'a, Vue.js uygulamalarınızın performansını optimize edin.

Vue 3 Pinia vs Vuex: Modern Durum Yönetimi ve Mülakat Soruları 2026
Pinia ve Vuex karşılaştırması: API tasarımı, TypeScript, Composition API entegrasyonu, performans, geçiş yolu ve 2026 Vue mülakat soruları.