# Vue 3 Composables Nâng Cao: Các Pattern Tái Sử Dụng và Câu Hỏi Phỏng Vấn 2026 > Phân tích chuyên sâu các composable nâng cao trong Vue 3 với pattern tái sử dụng, xử lý bất đồng bộ, dependency injection qua provide/inject, form validation và testing. Bao gồm câu hỏi phỏng vấn kỹ thuật cập nhật 2026. - Published: 2026-05-12 - Updated: 2026-05-12 - Author: SharpSkill - Tags: vue, composables, typescript, interview - Reading time: 12 min --- Composition API đã thay đổi căn bản cách lập trình viên Vue tổ chức và tái sử dụng logic trong ứng dụng frontend. Tại trung tâm của sự chuyển đổi này chính là **composable** — những hàm đóng gói trạng thái reactive, logic nghiệp vụ và side effects thành các đơn vị độc lập, có thể tái sử dụng ở bất kỳ đâu trong dự án. Khác với mixin của Vue 2 từng gây ra xung đột tên biến và phụ thuộc ngầm, composable mang đến sự minh bạch hoàn toàn, hỗ trợ static typing với TypeScript và cho phép kết hợp logic một cách tường minh. Năm 2026, hệ sinh thái Vue tiếp tục phát triển mạnh mẽ với những cải tiến đáng chú ý. Alien Signals — hệ thống reactivity mới được tích hợp vào Vue core — giúp giảm đáng kể memory footprint và tăng tốc độ tracking dependency. Song song đó, Vapor Mode đang dần hoàn thiện, cho phép compile component thành DOM operations trực tiếp mà không cần virtual DOM, mở ra tiềm năng tối ưu hiệu năng chưa từng có. Trong bối cảnh đó, việc nắm vững các pattern composable nâng cao trở thành yêu cầu bắt buộc đối với các vị trí phát triển Vue từ trung cấp trở lên. Bài viết này phân tích chi tiết các pattern composable được hỏi nhiều nhất trong phỏng vấn kỹ thuật, từ cấu trúc cơ bản của một composable chuẩn chỉnh cho đến dependency injection với `provide/inject`, kèm theo chiến lược testing kiểm chứng tính reactive của từng thành phần. > **Composable trong Vue 3 là gì?** > > Composable là một hàm sử dụng Composition API của Vue để đóng gói và tái sử dụng logic có trạng thái. Theo quy ước, tên composable bắt đầu bằng `use` (ví dụ: `useCounter`, `useFetch`). Mỗi composable trả về các ref reactive, computed và function mà component có thể sử dụng trực tiếp, không cần kế thừa hay ràng buộc ngầm định nào. ## Cấu Trúc Của Một Composable Chuẩn Một composable hiệu quả tuân theo các nguyên tắc rõ ràng: nhận cấu hình qua object có kiểu dữ liệu xác định, trả về interface tường minh và giữ trạng thái nội bộ cách ly hoàn toàn giữa các consumer. Ví dụ dưới đây triển khai một counter với giới hạn có thể cấu hình và giá trị computed phái sinh. ```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 } } ``` Có nhiều điểm đáng lưu ý trong pattern này. Interface `UseCounterReturn` định nghĩa tường minh contract của composable, hỗ trợ autocompletion trong editor và ngăn ngừa thay đổi vô tình trên API công khai. Object options với giá trị mặc định cho phép cấu hình linh hoạt mà không làm phức tạp chữ ký hàm. Mỗi lần gọi `useCounter()` tạo ra một instance trạng thái hoàn toàn độc lập, loại bỏ triệt để vấn đề shared state từng gây khó khăn với mixin. Pattern "options đầu vào, interface có kiểu đầu ra" này chính là nền tảng để xây dựng các composable phức tạp hơn. Khi Alien Signals được tích hợp hoàn toàn, cơ chế tracking bên trong `ref` và `computed` sẽ hoạt động hiệu quả hơn, nhưng cách viết composable vẫn giữ nguyên — đây là một trong những ưu điểm lớn của thiết kế API ổn định trong Vue. ## Composable Bất Đồng Bộ Với Xử Lý Lỗi Các thao tác mạng là một trong những use case phổ biến nhất cho composable. Pattern dưới đây triển khai hàm fetch reactive, tự động huỷ request đang thực hiện, xử lý lỗi chi tiết và phản ứng khi URL nguồn thay đổi. ```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 } } ``` Composable này giới thiệu một số khái niệm nâng cao. Kiểu `MaybeRefOrGetter` chấp nhận cả giá trị tĩnh lẫn ref reactive hoặc getter function, mang lại sự linh hoạt tối đa cho phía consumer. Hàm `toValue()` trích xuất giá trị bên trong bất kể kiểu đầu vào là gì. Việc sử dụng `AbortController` ngăn chặn race condition bằng cách huỷ request cũ khi URL thay đổi trước khi response trước đó kịp trả về. `watchEffect` thiết lập tracking reactive tự động: mọi ref hay getter được truy cập bên trong callback đều trở thành dependency. Nếu URL là một ref và giá trị của nó thay đổi, effect sẽ tự động chạy lại. Hook `onUnmounted` đảm bảo giải phóng tài nguyên khi component bị huỷ — một thực hành quan trọng để tránh memory leak trong single-page application. > **Lifecycle hook trong composable** > > Các hook như `onMounted`, `onUnmounted` và `watchEffect` chỉ hoạt động chính xác khi composable được gọi bên trong `setup()` hoặc `