01ref, reactive, computed และ watch

ref()

เหมาะกับค่าเดี่ยวและ object ที่อาจถูกแทนทั้งก้อน อ่านและเขียนผ่าน `.value` ใน JavaScript

reactive()

คืน Proxy ของ object เหมาะกับ state แบบกลุ่ม แต่ destructure property ตรง ๆ อาจทำให้หลุด reactivity

computed()

ใช้กับค่าที่ derive จาก state ไม่มี side effect และ cache จน dependency เปลี่ยน

watch()

ใช้ทำ side effect เช่นเรียก API, sync URL หรือ analytics และต้อง cleanup งานเก่า

use-policy-search.vue
<script setup lang="ts">
import { computed, onWatcherCleanup, ref, watch } from 'vue'

const query = ref('')
const policies = ref<Policy[]>([])

const activePolicies = computed(() =>
  policies.value.filter((item) => item.status === 'ACTIVE')
)

watch(query, async (value) => {
  const controller = new AbortController()
  onWatcherCleanup(() => controller.abort())

  policies.value = await searchPolicies(value, controller.signal)
})
</script>

ในตัวอย่าง `activePolicies` เป็นข้อมูลที่คำนวณจาก state จึงใช้ `computed` ส่วน search API เป็น side effect จึงใช้ `watch` และยกเลิก request เก่าเมื่อ query เปลี่ยน ป้องกัน race ที่ response เก่ากลับมาทับผลใหม่

02แบ่ง State ตามเจ้าของ

LOCAL

Component state

เปิด/ปิด dialog, form draft และ UI state ที่ไม่มี component อื่นต้องรู้

SHARED

Pinia

session, permission หรือ workflow ที่หลาย route และ component ใช้ร่วมกัน

SERVER

Remote data

ข้อมูลจาก API ที่มี loading, error, cache และ invalidation lifecycle ของตัวเอง

อย่าย้ายทุกอย่างเข้า global store เพราะทำให้ dependency ซ่อนอยู่และ lifecycle ยาวเกินจำเป็น เริ่มจาก state ที่ใกล้ผู้ใช้ที่สุด แล้วเลื่อนขึ้นเมื่อมี consumer ร่วมจริง

Composable ควรห่อ logic ที่ reuse ได้และมี contract ชัด ไม่ใช่แค่ย้ายโค้ดออกจาก component ถ้า composable เข้าถึง global store, router และ API พร้อมกันโดยซ่อน dependency ทั้งหมด การทดสอบและ reuse จะยากขึ้น

03Performance ที่ควรตรวจตามลำดับ

  1. 1
    วัดก่อน

    ใช้ Vue DevTools และ browser performance หา component ที่ update บ่อยจริง

  2. 2
    ลดงานที่ส่งลง client

    route lazy loading และ code splitting สำหรับ feature ใหญ่

  3. 3
    ลดจำนวน DOM

    virtualize list ยาว และใช้ stable key ที่แทน identity จริง

  4. 4
    ลด reactive overhead

    ข้อมูลก้อนใหญ่ที่ไม่ต้อง deep reactive ใช้ `shallowRef` หรือ mark raw อย่างมีเหตุผล

อย่า optimize ด้วย `v-memo`, shallow API หรือ manual cache ก่อนมี evidence เพราะ complexity ที่เพิ่มอาจแพงกว่าปัญหาเดิม โดยเฉพาะ component ที่ render ไม่บ่อย

04ตอบให้เห็นความเข้าใจ

อ่านเอกสารทางการ: Vue Reactivity in Depth