Skip to content

Nuxt.js State Management

ภาพรวม

Nuxt.js มีวิธีการจัดการ State หลายรูปแบบ ทั้งแบบ Built-in และการใช้ Library ภายนอก ซึ่งช่วยให้จัดการข้อมูลที่ใช้ร่วมกันในแอปพลิเคชันได้อย่างมีประสิทธิภาพ

ตัวเลือกการจัดการ State

1. useState (Built-in)

useState เป็น Composition API ที่มากับ Nuxt ใช้สำหรับจัดการ State แบบ Shared ระหว่างคอมโพเนนต์

typescript
// composables/states.ts
export const useCounter = () => useState<number>("counter", () => 0);

2. Pinia (แนะนำ)

State Management Library มาตรฐานของ Vue Ecosystem

bash
# ติดตั้ง Pinia
npx nuxi module add pinia

3. Library อื่นๆ

  • Harlem - สำหรับจัดการ State แบบ Immutable
  • XState - ใช้ State Machine ในการจัดการ State

ตารางเปรียบเทียบ

วิธีการใช้งานเหมาะกับข้อดีข้อเสีย
useStateง่าย, ใช้ได้ทันทีState น้อย, ไม่ซับซ้อนไม่ต้องติดตั้งเพิ่มไม่มี DevTools, จัดการ State ซับซ้อนยาก
Piniaต้องติดตั้งเพิ่มแอปขนาดใหญ่, ต้องการ DevToolsType Support ดี, มี DevToolsต้องเรียนรู้เพิ่มเล็กน้อย
XStateซับซ้อนState ซับซ้อน, ต้องการ State Machineควบคุมการเปลี่ยน State ได้ละเอียดเรียนรู้ยาก, Overkill สำหรับแอปเล็ก

ตัวอย่างการใช้งาน

1. ใช้ useState

vue
<!-- components/Counter.vue -->
<script setup lang="ts">
// เรียกใช้ State เดิมหรือสร้างใหม่ถ้ายังไม่มี
const counter = useState<number>("counter", () => 0);
</script>

<template>
  <div>
    <p>Counter: {{ counter }}</p>
    <button @click="counter++">+</button>
    <button @click="counter--">-</button>
  </div>
</template>

2. ใช้ Pinia

typescript
// stores/counter.ts
export const useCounterStore = defineStore("counter", {
  state: () => ({
    count: 0,
    name: "Counter",
  }),
  getters: {
    doubleCount: (state) => state.count * 2,
  },
  actions: {
    increment() {
      this.count++;
    },
    async fetchData() {
      const { data } = await useFetch("/api/counter");
      this.count = data.value?.count || 0;
    },
  },
});
vue
<!-- components/CounterPinia.vue -->
<script setup lang="ts">
const counterStore = useCounterStore();
</script>

<template>
  <div>
    <h2>{{ counterStore.name }}</h2>
    <p>Count: {{ counterStore.count }}</p>
    <p>Double: {{ counterStore.doubleCount }}</p>
    <button @click="counterStore.increment()">Increment</button>
    <button @click="counterStore.fetchData()">Fetch Data</button>
  </div>
</template>

Best Practices

1. การตั้งชื่อ State

typescript
// ดี
const user = useState("user");

// ไม่ดี (อาจเกิดการชนกันของชื่อ)
const data = useState("data");

2. ใช้ Composables จัดการ State

typescript
// composables/useAuth.ts
export const useAuth = () => {
  const user = useState("auth:user", () => null);
  const isAuthenticated = computed(() => !!user.value);

  const login = async (credentials) => {
    user.value = await $fetch("/api/login", {
      method: "POST",
      body: credentials,
    });
  };

  return {
    user,
    isAuthenticated,
    login,
  };
};

3. Server-Side State

typescript
// app.vue
const user = useAuthUser();

// ดึงข้อมูลผู้ใช้เมื่อโหลดหน้าเว็บ
await callOnce(async () => {
  if (process.server) {
    user.value = await $fetch("/api/me");
  }
});

การจัดการ State ขั้นสูง

1. Persist State

typescript
// plugins/persistState.client.ts
export default defineNuxtPlugin(() => {
  const auth = useAuthUser();

  // โหลด State จาก localStorage เมื่อเริ่มต้น
  if (process.client) {
    const saved = localStorage.getItem("auth");
    if (saved) {
      auth.value = JSON.parse(saved);
    }

    // บันทึก State เมื่อมีการเปลี่ยนแปลง
    watch(auth, (newValue) => {
      localStorage.setItem("auth", JSON.stringify(newValue));
    }, { deep: true });
  }
});

2. Hydration

typescript
// composables/useHydration.ts
export const useHydration = () => {
  // ใช้โหมด SSR
  const isHydrated = ref(false);

  onMounted(() => {
    isHydrated.value = true;
  });

  return {
    isHydrated,
  };
};

สรุป

  • ใช้ useState สำหรับ State ง่ายๆ ที่ไม่ซับซ้อน
  • ใช้ Pinia สำหรับแอปขนาดใหญ่ที่ต้องการความยืดหยุ่น
  • ใช้ XState เมื่อต้องการ State Machine
  • ควรแยกการจัดการ State ออกเป็น Modules หรือ Composables
  • ระวังเรื่อง Hydration เมื่อใช้ SSR

TIP

  • ใช้ TypeScript เพื่อความปลอดภัยของประเภทข้อมูล
  • ใช้ DevTools เพื่อตรวจสอบ State
  • ทดสอบการทำงานของ State Management ให้ครบทุกกรณี