- Vue.js là gì? Khác React/Angular thế nào?
Vue.js là progressive JavaScript framework để xây dựng UI. (1) So với React: Vue có template syntax rõ ràng hơn, two-way binding tích hợp sẵn, learning curve thấp hơn; React dùng JSX, unidirectional flow, hệ sinh thái lớn hơn (2) So với Angular: Vue nhẹ…
- Options API vs Composition API — khác nhau gì?
Options API (Vue 2 style): tổ chức code theo loại (data, methods, computed, watch). Composition API (Vue 3): tổ chức code theo logic concern, dùng setup() hoặc <script setup. (1) Composition API dễ tái sử dụng logic hơn qua composables (2) TypeScript support tốt hơn…
- `<script setup>` là gì? Lợi ích so với `setup()` thông thường?
<script setup là syntactic sugar cho Composition API — tất cả code bên trong tự động expose ra template mà không cần return. (1) Gọn hơn: không cần export default, không cần return (2) Hiệu năng tốt hơn: compiler tối ưu hoá tốt hơn (3)…
- Single File Component (SFC) là gì?
SFC (.vue file) gom template, script, style vào một file duy nhất — tiện lợi cho development. Cấu trúc: <template (HTML), <script setup (logic), <style scoped (CSS). (1) scoped attribute: CSS chỉ áp dụng cho component đó, tránh conflict (2) Compiler (Vite/webpack) parse và compile…
- Các directive phổ biến trong Vue: v-if, v-show, v-for, v-model, v-bind, v-on?
Vue directives là các HTML attribute đặc biệt gắn kết reactive behavior vào DOM. Phổ biến nhất: v-if/v-else/v-else-if: điều kiện render, xoá/tạo DOM thật. v-show: ẩn bằng display:none, DOM vẫn tồn tại. v-for: loop render, luôn cần :key. v-model: two-way binding cho input. v-bind (:attr):…
- v-if vs v-show — khi nào dùng cái nào?
v-if: xoá hoàn toàn DOM khi false — chi phí cao khi toggle thường xuyên, nhưng không render child khi không cần (lazy). v-show: chỉ toggle display:none — DOM luôn được render, chi phí thấp khi toggle. Dùng v-show khi element cần toggle thường xuyên.…
- Tại sao `:key` trong `v-for` quan trọng?
Vue dùng :key để identify mỗi vnode khi diff — giúp tái sử dụng và reorder DOM nodes đúng cách thay vì re-render toàn bộ. (1) Thiếu key: Vue dùng "in-place patch" — có thể gây lỗi với stateful components hoặc animation (2) Dùng index…
- v-model hoạt động thế nào? Custom v-model?
v-model là shorthand: :modelValue + @update:modelValue. Mặc định cho input: Custom component v-model: Vue 3 hỗ trợ multiple v-model: v-model:title, v-model:content với props tương ứng.
- Reactivity system trong Vue 3 hoạt động thế nào?
Vue 3 dùng ES6 Proxy để intercept get/set operations trên reactive objects. Khi đọc property trong effect (computed, watcher, render): dependency được track. Khi set property: trigger cập nhật tất cả dependents. Cải tiến so với Vue 2 (dùng Object.defineProperty): (1) Detect thêm/xoá property động…
- `ref` vs `reactive` — khác nhau gì? Dùng khi nào?
ref: wrap bất kỳ giá trị nào (primitives, objects) thành reactive container — truy cập qua .value trong script, tự unwrap trong template. reactive: wrap object/array thành reactive Proxy — truy cập trực tiếp, không cần .value. Khuyến nghị hiện tại (Vue 3.2+): Dùng ref…
- `computed` vs `watch` vs `watchEffect` — dùng khi nào?
computed: derive giá trị từ reactive state, kết quả được cache, chỉ recompute khi dependency thay đổi — dùng để transform/calculate data cho template. watch: observe cụ thể một hoặc vài sources, có access vào old/new value, lazy by default — dùng khi cần side…
- Composable là gì? So sánh với Mixins?
Composable là function dùng Composition API để đóng gói và tái sử dụng stateful logic. Ví dụ: So với Mixins: (1) Không có naming collision — return value rõ ràng (2) Source rõ ràng — biết data từ đâu (3) Có thể nhận arguments (dynamic)…
- Lifecycle hooks trong Composition API?
Trong <script setup, lifecycle hooks được import và dùng như functions: Mapping từ Options API (bao gồm Vue 2 → Vue 3): beforeCreate/created → code trong setup() chạy thay thế, mounted → onMounted, updated → onUpdated, beforeUpdate → onBeforeUpdate, unmounted → onUnmounted, beforeMount → onBeforeMount.…
- `provide` / `inject` là gì? Khi nào dùng?
provide / inject cho phép truyền data qua component tree mà không cần props drilling. Parent provide, bất kỳ descendant nào có thể inject: Dùng khi: (1) Shared state cho subtree (theme, locale, auth) (2) Plugin/library cung cấp context. Lưu ý: khó debug hơn props…
- `defineProps` và `defineEmits` trong `<script setup>`?
defineProps khai báo props mà component nhận, defineEmits khai báo events mà component emit: Lưu ý: defineProps không thể destructure trực tiếp mà giữ reactivity trong Vue 3.4 trở về trước — dùng toRefs(props). Từ Vue 3.5+: destructure props với const { title } =…
- Các cách truyền data giữa components trong Vue?
Vue components giao tiếp qua nhiều cơ chế tuỳ quan hệ và chiều dữ liệu. (1) Props (parent → child): dữ liệu đi xuống, one-way (2) Emits (child → parent): event đi lên, gọi emit() (3) v-model: two-way binding, kết hợp props + emits (4)…
- Slots là gì? Named slots và scoped slots?
Slots cho phép parent inject content vào template của child component. Default slot: <slot /. Named slots: <slot name="header" / — parent dùng <template header. Scoped slot: child truyền data lên parent qua slot: Dùng scoped slots khi child biết cách lấy data nhưng parent…
- `defineExpose` trong `<script setup>` là gì?
Trong <script setup, component instance mặc định không expose properties ra ngoài (không access được qua template ref). defineExpose cho phép explicitly expose các methods/properties để parent gọi qua ref. Ví dụ: defineExpose({ focus, reset }) — parent gọi childRef.value.focus(). Dùng khi cần imperative control…
- Vue Router cơ bản: cách setup và navigate?
Vue Router là official router cho Vue.js — quản lý navigation, URL history, route matching. Navigate: <RouterLink to="/about" trong template, hoặc router.push('/about') trong script. <RouterView / là nơi component được render.
- Navigation guards là gì? beforeEach, beforeEnter, beforeRouteEnter?
Navigation guards cho phép control navigation — xác thực, redirect, cancel. In-component guards (Options API): beforeRouteEnter, beforeRouteUpdate, beforeRouteLeave. Trong Composition API dùng onBeforeRouteLeave, onBeforeRouteUpdate. Return false để cancel, return route location để redirect, return undefined/true để proceed.
- Dynamic routes và lazy loading routes?
Dynamic segment: path: '/user/:id' — đọc qua route.params.id. Lazy loading với dynamic import: Lazy loading: component chỉ được download khi navigate đến route đó — giảm initial bundle size. Lưu ý: / webpackChunkName / là Webpack magic comment, không có tác dụng trong Vite. Lưu…
- Pinia là gì? Tại sao thay thế Vuex?
Pinia là official state management library cho Vue 3 — thay thế Vuex. Ưu điểm: (1) Composition API-friendly, không cần mutations (2) TypeScript support tốt hơn nhiều (3) Không có nested modules, mỗi store là một module độc lập (4) Bundle nhỏ hơn (~1KB) (5)…
- Cách tạo và dùng Pinia store?
Pinia stores được tạo với defineStore() dùng setup-store syntax (khuyến nghị), trả về refs cho state, computed getters, và action functions. Lưu ý: destructure store mất reactivity — dùng storeToRefs: const { count, double } = storeToRefs(store) (methods thì destructure thường).
- `storeToRefs` là gì? Tại sao cần?
Pinia store là reactive object — destructuring trực tiếp sẽ mất reactivity (tương tự reactive()). storeToRefs() convert state và getters thành refs để destructure an toàn: const { count, name } = storeToRefs(store). Methods (actions) không cần storeToRefs — destructure thường: const { increment }…
- Persist Pinia store với localStorage?
- `v-memo` directive là gì?
v-memo skip re-render một subtree nếu array dependency không thay đổi — tương tự React.memo nhưng ở template level: Dùng cho: (1) Long lists với expensive child renders (2) Chỉ một vài properties ảnh hưởng đến render. Lưu ý: không lạm dụng — dependency array…
- KeepAlive component là gì?
<KeepAlive cache component instance khi unmount — state được giữ nguyên khi switch lại: Lifecycle hooks cho cached components: onActivated (khi cache hit, component show lại), onDeactivated (khi bị hide, không unmount). Dùng cho: tab views, multi-step forms, expensive components cần giữ state. Lưu ý:…
- Teleport component là gì? Use case?
- Suspense component là gì?
- Lazy loading components trong Vue?
Dùng dynamic import để lazy load component — chỉ download khi cần: Kết hợp với <Suspense để handle loading state elegantly.
- Custom directives trong Vue 3?
- Vue 3 vs Vue 2 — những thay đổi lớn nhất?
- SSR với Nuxt.js — Vue SSR hoạt động thế nào?
- Error handling trong Vue: errorCaptured và onErrorCaptured?
Vue cung cấp error boundary mechanism qua errorCaptured (Options API) / onErrorCaptured (Composition API): Global handler: app.config.errorHandler = (err, instance, info) = { ... }. Error types caught: lifecycle hooks, event handlers, async errors trong setup, child component errors. Lưu ý: không catch errors trong…
- Render functions và h() trong Vue 3?
- Testing Vue components với Vitest và Vue Test Utils?
Vue components được test bằng cách mount chúng với @vue/test-utils và assert trên rendered output và emitted events, dùng Vitest làm test runner. Dùng shallowMount để stub child components. Test behavior, không test implementation details.
- `nextTick` là gì? Khi nào dùng?
Vue batch DOM updates — không update ngay khi state thay đổi, mà queue updates và flush async. nextTick cho phép chờ DOM được update xong: Dùng khi: (1) Cần đọc DOM sau khi state update (2) Focus element sau khi v-if toggle (3) Scroll…
- Transition và TransitionGroup trong Vue?
- Vue 3 performance optimization best practices?
- `toRef`, `toRefs`, `toValue` — dùng khi nào?
toRef: tạo ref từ một property của reactive object — giữ reactive connection: toRefs: convert toàn bộ reactive object thành object of refs — dùng khi destructure: toValue (Vue 3.3+): unwrap ref hoặc getter — dùng trong composables để accept cả ref và plain value:
- accessiblity (a11y) trong Vue — best practices?
Vue a11y best practices theo chuẩn ARIA và semantic HTML, kết hợp Vue-specific tooling như vue-axe và eslint-plugin-vuejs-accessibility để phát hiện vấn đề sớm. (1) Dùng semantic HTML trong templates (<button không phải <div @click) (2) :aria-label, :aria-expanded, :aria-live với dynamic content (3) Focus management…
- Template refs — cách truy cập DOM element và child component trong Vue 3?
Template ref cho phép truy cập DOM element hoặc component instance trực tiếp: Lưu ý: ref.value là null trước khi component mount — luôn kiểm tra trong onMounted hoặc dùng optional chaining ref.value?.method().
- Cách fetch async data đúng cách trong Vue 3 Composition API?
Pattern chuẩn để fetch async data trong Vue 3 Composition API là dùng onMounted với try/catch/finally, hoặc trích xuất thành composable tái sử dụng. Lưu ý: không gọi async setup() trực tiếp mà không có <Suspense bọc ngoài — dùng onMounted hoặc composable thay. Với…
- Hydration mismatch trong Nuxt/Vue SSR — nguyên nhân và cách fix?
- Nuxt 3 data fetching — useFetch vs useAsyncData vs $fetch?
- `shallowRef`, `shallowReactive`, `markRaw` — khi nào dùng để tối ưu?
- Ref unwrapping trong templates và reactive objects hoạt động thế nào?
Vue tự động unwrap refs trong một số contexts — hiểu rõ để tránh bugs: Template auto-unwrap: refs được auto-unwrap trong template, không cần .value: Reactive object unwrap: ref là property của reactive object được tự động unwrap khi access: Không unwrap: ref trong array…
- Pinia plugins — cách tạo custom plugin và use cases?
- Route meta và type-safe route meta trong Vue Router 4?
Route meta cho phép đính kèm custom data vào routes — thường dùng cho auth, breadcrumbs, page titles: Lưu ý: to.meta tổng hợp metadata từ tất cả matched routes (parent + child) — child ghi đè parent.
- Scroll behavior trong Vue Router — restore scroll position?
Vue Router cho phép kiểm soát scroll behavior khi navigate: Dùng savedPosition để implement proper back/forward scroll restoration — trải nghiệm native-like.
- `watchEffect` deep dive — cleanup, flush timing và stop watcher?
- Typed `provide` / `inject` với InjectionKey — best practice?
Dùng InjectionKey để provide/inject type-safe, tránh string key collisions: Dùng Symbol làm key thay vì string để tránh naming collision trong large apps hoặc libraries.
- `v-once` và `v-pre` — dùng khi nào để skip rendering?
v-once: render element/component một lần duy nhất — skip future updates. Sau khi render, element được xử lý như static content: v-pre: skip compilation toàn bộ subtree — dùng cho content muốn hiển thị mustache syntax như raw text: Khác nhau: v-once render rồi freeze…
- Virtual scrolling trong Vue — xử lý large lists hiệu quả?
- v-model modifiers — built-in và custom modifiers?
Built-in modifiers: - .lazy: sync sau change event thay vì input — giảm updates - .number: auto convert sang number (tương đương parseFloat) - .trim: auto trim whitespace Custom modifiers cho component v-model:
- Nuxt 3 middleware — route middleware vs server middleware?
- Vì sao không nên đặt `v-if` và `v-for` trên cùng một thẻ? Viết lại thế nào cho đúng?
Vì trong Vue 3, v-if có độ ưu tiên cao hơn v-for — điều kiện được đánh giá trước, nên nó không nhìn thấy biến của vòng lặp. Đoạn dưới ném lỗi vì user chưa tồn tại ở thời điểm v-if chạy: Hai cách sửa:…
- Vì sao gán trực tiếp vào `props` bị cảnh báo? Con muốn sửa dữ liệu cha truyền xuống thì làm thế nào?
Vue áp dụng one-way data flow: props chỉ truyền từ cha xuống con. Gán props.title = ... sẽ bị Vue cảnh báo (và ở chế độ dev là lỗi) vì mỗi lần cha re-render, giá trị đó bị ghi đè lại — sửa ở con…
- Vì sao destructure một object `reactive` (hoặc `props`) lại mất reactivity? Cách giữ lại?
Vì reactive() trả về một Proxy — reactivity nằm ở thao tác truy cập thuộc tính qua proxy, không nằm trong giá trị. Destructure lấy ra giá trị nguyên thuỷ tại thời điểm đó, cắt đứt liên kết với proxy: Cách giữ liên kết: Với…
- `watch` trên một object: khi nào cần `deep`, vì sao `oldValue` lại bằng `newValue`, và `flush` ảnh hưởng gì?
Ba điểm hay vướng khi watch dữ liệu dạng object: 1. deep. watch một ref chứa object chỉ chạy khi thay cả object (obj.value = {...}). Đổi thuộc tính bên trong thì không kích hoạt — trừ khi bật { deep: true }. Riêng khi…
- `defineModel` khác gì so với tự viết `props` + `emit('update:modelValue')` khi làm `v-model` cho component?
defineModel() là macro (ổn định từ Vue 3.4) gói lại đúng cặp prop + emit mà trước đây phải khai báo tay, và trả về một ref hai chiều. Khác biệt đáng nói: - Ghi model.value = x sẽ tự emit update:modelValue; đọc model.value lấy…
- Setup store (composition-style) trong Pinia khác option store thế nào? Có hạn chế gì?
Setup store dùng đúng cú pháp setup(): ref là state, computed là getter, function là action. Cuối hàm phải return những gì muốn công khai. So với option store ({ state, getters, actions }): - Linh hoạt hơn: dùng được watch, composable khác, hoặc tạo…
- Vì sao composable phải được gọi đồng bộ trong `setup`? Điều gì hỏng nếu gọi sau `await`?
- Bảng 20.000 dòng render chậm và tốn RAM: `shallowRef` / `markRaw` giúp gì? `triggerRef` dùng khi nào?