Vue 3 Reactivity Transform ในปี 2026: $ref, $computed และคำถามสัมภาษณ์งาน
คู่มือเชิงลึกเกี่ยวกับ Reactivity Transform ใน Vue 3 ครอบคลุม $ref, $computed และคำถามสัมภาษณ์ที่พบบ่อยสำหรับนักพัฒนา Vue ระดับสูง

Reactivity Transform เป็นฟีเจอร์ทดลองใน Vue 3 ที่มีจุดประสงค์เพื่อทำให้การใช้งาน reactive state ง่ายขึ้นโดยไม่ต้องเข้าถึง .value บน ref การทำความเข้าใจแนวคิดและทางเลือกอื่นยังคงมีคุณค่าในการสัมภาษณ์นักพัฒนา Vue เนื่องจากแสดงให้เห็นถึงความรู้เชิงลึกเกี่ยวกับระบบ reactivity ของ Vue แม้ว่าฟีเจอร์นี้จะถูกลบออกจาก Vue core ตั้งแต่เวอร์ชัน 3.4
Reactivity Transform ($ref, $computed) ถูกลบออกจาก Vue 3.4 เป็นต้นไป Vue Macros มี implementation จากชุมชนสำหรับทีมที่ยังต้องการใช้งาน การเข้าใจแนวคิดนี้ยังคงมีคุณค่าสำหรับการสัมภาษณ์เพราะแสดงความรู้เกี่ยวกับวิวัฒนาการของ Vue
ทำความเข้าใจปัญหาที่ Reactivity Transform แก้ไข
ระบบ reactivity ของ Vue 3 อิงกับอ็อบเจกต์ ref และ reactive เมื่อใช้ ref นักพัฒนาต้องเข้าถึงค่าผ่าน property .value ใน script ในขณะที่ใน template การเข้าถึงโดยตรงโดยไม่ต้องใช้ .value เป็นไปได้เนื่องจาก unwrapping อัตโนมัติ
import { ref, computed } from 'vue'
// วิธีการมาตรฐานกับ .value
const count = ref(0)
const doubled = computed(() => count.value * 2)
function increment() {
count.value++
console.log(doubled.value)
}Reactivity Transform ลบ boilerplate .value ด้วย macro ของ compiler ที่แปลงโค้ดในเวลา build
// กับ Reactivity Transform (deprecated)
let count = $ref(0)
const doubled = $computed(() => count * 2)
function increment() {
count++
console.log(doubled)
}วิธีการทำงานของ $ref และ $computed
Macro $ref ประกาศตัวแปร reactive ที่สามารถใช้งานได้เหมือนตัวแปร JavaScript ปกติ Compiler ของ Vue แปลงโค้ดนี้เป็นการใช้งาน ref มาตรฐานพร้อม .value ที่เหมาะสม
// Source code กับ $ref
let username = $ref('')
let isValid = $computed(() => username.length >= 3)
function updateUsername(value: string) {
username = value
}
// ผลลัพธ์หลังจาก compiler transform
import { ref, computed } from 'vue'
const username = ref('')
const isValid = computed(() => username.value.length >= 3)
function updateUsername(value: string) {
username.value = value
}Macro $$ สำหรับ Escape Ref
Macro $$ อนุญาตให้เข้าถึงอ็อบเจกต์ ref ที่อยู่ภายใต้เมื่อจำเป็น เช่น เมื่อส่ง ref ไปยัง composable หรือ watch
import { watch } from 'vue'
let count = $ref(0)
// ใช้ $$ เพื่อรับ ref object
watch($$(count), (newVal, oldVal) => {
console.log(`Count เปลี่ยนจาก ${oldVal} เป็น ${newVal}`)
})
// ส่ง ref ไปยัง composable
function useDoubled(countRef: Ref<number>) {
return computed(() => countRef.value * 2)
}
const doubled = useDoubled($$(count))Reactive Props Destructure
Vue 3.5 แนะนำ destructuring props แบบ reactive เป็นฟีเจอร์ที่เสถียร ทดแทนบางส่วนของฟังก์ชันการทำงานของ Reactivity Transform สำหรับ props
<script setup lang="ts">
// Vue 3.5+ reactive props destructure
const { count = 0, title } = defineProps<{
count?: number
title: string
}>()
// count และ title ยังคง reactive
const doubled = computed(() => count * 2)
</script>
<template>
<h1>{{ title }}</h1>
<p>Count: {{ count }}, Doubled: {{ doubled }}</p>
</template>ก่อน Vue 3.5 การ destructuring props ทำให้สูญเสีย reactivity และต้องใช้ toRefs:
const props = defineProps<{ count: number }>()
const { count } = toRefs(props) // จำเป็นเพื่อรักษา reactivityImplementation ทางเลือกด้วย Vue Macros
Vue Macros เป็นคอลเลกชันของ macro ที่ดูแลโดยชุมชน ให้ฟังก์ชันการทำงานของ Reactivity Transform และฟีเจอร์เพิ่มเติมอื่นๆ
import Vue from '@vitejs/plugin-vue'
import VueMacros from 'unplugin-vue-macros/vite'
export default defineConfig({
plugins: [
VueMacros({
plugins: {
vue: Vue(),
},
}),
],
})<script setup lang="ts">
// กับ Vue Macros
let count = $ref(0)
let items = $ref<string[]>([])
const total = $computed(() => items.length)
const isEmpty = $computed(() => total === 0)
function addItem(item: string) {
items = [...items, item]
count++
}
</script>Pattern สมัยใหม่โดยไม่ต้องใช้ Reactivity Transform
วิธีการที่แนะนำใน Vue 3.5 ใช้ฟีเจอร์ built-in โดยไม่ต้องใช้ macro ภายนอก
<script setup lang="ts">
import { ref, computed, watch } from 'vue'
// หลักการตั้งชื่อ: ใช้ suffix Ref เพื่อความชัดเจน
const countRef = ref(0)
const itemsRef = ref<string[]>([])
// Computed properties
const total = computed(() => itemsRef.value.length)
const isEmpty = computed(() => total.value === 0)
// Composable กับ reactive state
function useCounter(initialValue = 0) {
const count = ref(initialValue)
const increment = () => count.value++
const decrement = () => count.value--
const reset = () => count.value = initialValue
return {
count,
increment,
decrement,
reset
}
}
const { count, increment, decrement } = useCounter(10)
</script>เปรียบเทียบ ref vs reactive
การเข้าใจว่าควรใช้ ref เมื่อใดเทียบกับ reactive มักปรากฏในการสัมภาษณ์ Vue
import { ref, reactive, toRefs } from 'vue'
// ref: สำหรับ primitive values และ single values
const count = ref(0)
const name = ref('Vue')
const isLoading = ref(false)
// reactive: สำหรับ objects ที่มีหลาย properties
const state = reactive({
user: null as User | null,
posts: [] as Post[],
pagination: {
page: 1,
perPage: 10
}
})
// Destructure reactive object ด้วย toRefs
const { user, posts } = toRefs(state)
// ข้อดีของ ref:
// 1. สามารถ reassign ได้ทั้งหมด
// 2. สามารถส่งไปยัง functions โดยไม่สูญเสีย reactivity
// 3. คาดเดาได้มากกว่ากับ TypeScript
// ข้อดีของ reactive:
// 1. ไม่ต้องใช้ .value สำหรับ nested access
// 2. เป็นธรรมชาติมากกว่าสำหรับ complex state objects
// 3. Automatic unwrapping ใน templateAdvanced Reactivity Patterns
Pattern ขั้นสูงที่มักถูกถามในการสัมภาษณ์นักพัฒนา Vue ระดับสูง
Custom Ref พร้อม Validation
import { customRef } from 'vue'
function useDebouncedRef<T>(value: T, delay = 300) {
let timeout: ReturnType<typeof setTimeout>
return customRef<T>((track, trigger) => ({
get() {
track()
return value
},
set(newValue: T) {
clearTimeout(timeout)
timeout = setTimeout(() => {
value = newValue
trigger()
}, delay)
}
}))
}
// การใช้งาน
const searchQuery = useDebouncedRef('', 500)Shallow Reactivity สำหรับ Performance
import { shallowRef, shallowReactive, triggerRef } from 'vue'
// shallowRef: เฉพาะ level แรกที่เป็น reactive
const largeList = shallowRef<Item[]>([])
function updateList(items: Item[]) {
largeList.value = items // Triggers update
}
function mutateItem(index: number) {
largeList.value[index].name = 'Updated'
triggerRef(largeList) // ต้อง trigger แบบ manual
}
// shallowReactive: เฉพาะ properties level แรกที่เป็น reactive
const config = shallowReactive({
theme: 'dark',
settings: { /* nested ไม่ reactive */ }
})พร้อมที่จะพิชิตการสัมภาษณ์ Vue.js / Nuxt.js แล้วหรือยังครับ?
ฝึกฝนด้วยตัวจำลองแบบโต้ตอบ, flashcards และแบบทดสอบเทคนิคครับ
คำถามสัมภาษณ์ Vue Reactivity
คำถามที่ 1: อธิบายความแตกต่างระหว่าง ref และ reactive
คำตอบที่คาดหวัง: ref ห่อค่าใดๆ (primitive หรือ object) ในอ็อบเจกต์ที่มี property .value ในขณะที่ reactive สร้าง proxy แบบ reactive จาก object ref ยืดหยุ่นกว่าเพราะสามารถเก็บ primitive และสามารถ reassign ได้ทั้งหมด reactive เป็นมิตรกับการใช้งานมากกว่าสำหรับ complex nested objects แต่ไม่สามารถ reassign ได้และสูญเสีย reactivity ถ้า destructure โดยไม่มี toRefs
คำถามที่ 2: ทำไม Reactivity Transform ถึงถูกลบออกจาก Vue core?
คำตอบที่คาดหวัง: ทีม Vue ตัดสินใจลบ Reactivity Transform เนื่องจากหลายเหตุผล: เพิ่ม mental complexity โดยการผสม model reactivity สองแบบ ต้องการ tooling พิเศษที่ไม่เสมอไปมีให้ใช้ และทำให้ debugging ยากขึ้นเพราะโค้ดที่เขียนต่างจากโค้ดที่รัน ฟีเจอร์ reactive props destructure ใน Vue 3.5 แก้ไข use case ที่พบบ่อยที่สุดโดยไม่ต้องใช้ macro แบบ global
คำถามที่ 3: วิธีรักษา reactivity เมื่อ destructuring?
// คำถาม: แก้โค้ดนี้ให้ reactive
const state = reactive({ count: 0, name: 'Vue' })
const { count, name } = state // ไม่ reactive!
// คำตอบ:
import { toRefs } from 'vue'
const state = reactive({ count: 0, name: 'Vue' })
const { count, name } = toRefs(state) // ตอนนี้ reactive แล้ว
// หรือใช้ computed สำหรับ derived values
const count = computed(() => state.count)คำถามที่ 4: ควรใช้ shallowRef vs ref เมื่อใด?
คำตอบที่คาดหวัง: ใช้ shallowRef เมื่อทำงานกับ large objects หรือ arrays ที่มักถูก replace ทั้งหมดแต่ไม่ค่อยถูก mutate ภายใน สิ่งนี้หลีกเลี่ยง overhead จาก deep reactivity tracking ตัวอย่าง use case: large API response, large datasets สำหรับตาราง หรือ state ที่จัดการโดย external library
คำถามที่ 5: Implement computed writable
import { ref, computed } from 'vue'
const firstName = ref('John')
const lastName = ref('Doe')
const fullName = computed({
get() {
return `${firstName.value} ${lastName.value}`
},
set(value: string) {
const parts = value.split(' ')
firstName.value = parts[0] || ''
lastName.value = parts.slice(1).join(' ') || ''
}
})
// การใช้งาน
fullName.value = 'Jane Smith' // firstName = 'Jane', lastName = 'Smith'Best Practices Reactivity Vue 3
-
ให้ความสำคัญกับ ref สำหรับ composables: คืนค่า
refจาก composables เพราะ destructure ง่ายกว่าและยังคง reactive -
ใช้ readonly สำหรับข้อมูลที่ไม่ควรถูก mutate:
readonly(state)ป้องกันการ mutation ที่ไม่ได้ตั้งใจ -
หลีกเลี่ยง deep reactivity ที่ไม่จำเป็น: ใช้
shallowRefหรือmarkRawสำหรับข้อมูลที่ไม่ต้องการ reactive -
สม่ำเสมอกับหลักการตั้งชื่อ: เพิ่ม suffix เช่น
RefหรือStateเพื่อความชัดเจน -
ใช้ประโยชน์จาก TypeScript: กำหนด types สำหรับ ref generics เพื่อป้องกัน runtime errors
สรุป
แม้ว่า Reactivity Transform ถูกลบออกจาก Vue core แล้ว การเข้าใจแนวคิดเบื้องหลังให้ข้อมูลเชิงลึกที่มีคุณค่าเกี่ยวกับระบบ reactivity ของ Vue ฟีเจอร์สมัยใหม่เช่น reactive props destructure ใน Vue 3.5 ให้ความสะดวกในการใช้งานที่ดีกว่าโดยไม่มีความซับซ้อนเพิ่มเติมจาก macro compiler ในการสัมภาษณ์ ความสามารถในการอธิบาย trade-off ของวิธีการ reactivity ต่างๆ แสดงให้เห็นถึงความเข้าใจอย่างลึกซึ้งเกี่ยวกับ Vue internals
คุณหาบั๊กใน Vue.js / Nuxt.js เจอไหม
โค้ดจริงหนึ่งชิ้น บั๊กที่ซ่อนอยู่หนึ่งจุด วันละหนึ่งครั้ง ลองได้โดยไม่ต้องมีบัญชี

เขียนโดย
Anthony Fillion-Mailletผู้ก่อตั้ง SharpSkill
เป็นนักพัฒนาฟูลสแตกมากว่า 10 ปี ดูแล SharpSkill และรับผิดชอบทุกสิ่งที่เผยแพร่ที่นี่
อัปเดตเมื่อ 9 กันยายน 2569
แท็ก
แชร์
บทความที่เกี่ยวข้อง

Vue 3 Composition API: คู่มือฉบับสมบูรณ์เพื่อเชี่ยวชาญระบบ Reactivity
เชี่ยวชาญ Vue 3 Composition API ผ่านคู่มือเชิงปฏิบัตินี้ เรียนรู้ ref, reactive, computed, watch และ composables เพื่อสร้างแอปพลิเคชัน Vue ที่มีประสิทธิภาพสูง

Vue 3 Composables ขั้นสูง: รูปแบบการใช้ซ้ำและคำถามสัมภาษณ์งาน 2026
คู่มือ Vue 3 Composables ขั้นสูงฉบับสมบูรณ์: รูปแบบการใช้ซ้ำ การจัดการ Async การ Inject Dependencies การตรวจสอบฟอร์ม และคำถามสัมภาษณ์งานเทคนิคปี 2026

Vue 3 Script Setup และ defineModel ในปี 2026: ไวยากรณ์สมัยใหม่และคำถามสัมภาษณ์งาน
คู่มือฉบับสมบูรณ์เกี่ยวกับไวยากรณ์ script setup ของ Vue 3, defineModel สำหรับ two-way binding, reactive props destructure ใน Vue 3.5 และคำถามสัมภาษณ์ที่พบบ่อย