[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M79AEXMYAR1GZGS1MWWKVBZ7":3,"skill-same:01M79AEXMYAR1GZGS1MWWKVBZ7":85},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":19,"linkOnly":20,"markdownContent":21,"markdownBody":22,"frontMatter":23,"refName":49,"commitSha":50,"skillDirectory":51,"forksCount":14,"repositoryHtmlUrl":52,"repositoryHomepageUrl":6,"ownerHtmlUrl":53,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":54,"install":55,"resources":68},"01M79AEXMYAR1GZGS1MWWKVBZ7","nuxt-data",null,"| Nuxt 4 data management: composables, data fetching with useFetch\u002FuseAsyncData, and state management with useState and Pinia. Use when: creating custom composables, fetching data with useFetch or useAsyncData, managing global state with useState, integrating Pinia, debugging reactive data issues, or implementing SSR-safe state patterns.","Elogic360\u002Fsoftware-factory","Elogic360","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F156535519?v=4","01M74NH3F0RB13PWB7JZDE2V80","elogic360","01M74NH3FPC65082MDZVMFHDM3",0,"MIT","https:\u002F\u002Fgithub.com\u002FElogic360\u002Fsoftware-factory\u002Fblob\u002Fmain\u002Fintegrations\u002Fclaude-skills-secondsky\u002Fplugins\u002Fnuxt-v4\u002Fskills\u002Fnuxt-data\u002FSKILL.md",[],[],"2026-11-15 14:19:17",false,"---\nname: nuxt-data\ndescription: \"| Nuxt 4 data management: composables, data fetching with useFetch\u002FuseAsyncData, and state management with useState and Pinia. Use when: creating custom composables, fetching data with useFetch or useAsyncData, managing global state with useState, integrating Pinia, debugging reactive data issues, or implementing SSR-safe state patterns.\"\nlicense: MIT\nmetadata:\n  version: 4.0.0\n  author: Claude Skills Maintainers\n  category: Framework\n  framework: Nuxt\n  framework-version: 4.x\n  last-verified: 2025-12-28\n  keywords:\n    - useFetch\n    - useAsyncData\n    - $fetch\n    - useState\n    - composables\n    - Pinia\n    - data fetching\n    - state management\n    - reactive\n    - shallow reactivity\n    - reactive keys\n    - transform\n    - pending\n    - error\n    - refresh\n    - dedupe\n    - caching\n---\n# Nuxt 4 Data Management\n\nComposables, data fetching, and state management patterns for Nuxt 4 applications.\n\n## Quick Reference\n\n### Data Fetching Methods\n\n| Method | Use Case | SSR | Caching | Reactive |\n|--------|----------|-----|---------|----------|\n| `useFetch` | Simple API calls | Yes | Yes | Yes |\n| `useAsyncData` | Custom async logic | Yes | Yes | Yes |\n| `$fetch` | Client-side only, events | No | No | No |\n\n### Composable Naming\n\n| Prefix | Purpose | Example |\n|--------|---------|---------|\n| `use` | State\u002Flogic composable | `useAuth`, `useCart` |\n| `fetch` | Data fetching only | `fetchUsers` (rare) |\n\n## When to Load References\n\n**Load `references\u002Fcomposables.md` when:**\n- Writing custom composables with complex state\n- Debugging state management issues or memory leaks\n- Implementing SSR-safe patterns with browser APIs\n- Building authentication or complex state composables\n- Understanding singleton vs per-call composable patterns\n\n**Load `references\u002Fdata-fetching.md` when:**\n- Implementing API data fetching with reactive parameters\n- Troubleshooting shallow vs deep reactivity issues\n- Debugging data not refreshing when params change\n- Implementing pagination, infinite scroll, or search\n- Understanding transform functions, caching, or error handling\n\n**Load `references\u002Fpinia-integration.md` when:**\n- Setting up Pinia for complex state management\n- Creating stores with getters and actions\n- Integrating Pinia with SSR\n- Persisting state across page reloads\n\n## Composables\n\n### useState - The Foundation\n\n`useState` creates SSR-safe, shared reactive state that persists across component instances.\n\n```typescript\n\u002F\u002F composables\u002FuseCounter.ts\nexport const useCounter = () => {\n  \u002F\u002F Singleton - shared across all components\n  const count = useState('counter', () => 0)\n\n  const increment = () => count.value++\n  const decrement = () => count.value--\n  const reset = () => count.value = 0\n\n  return { count, increment, decrement, reset }\n}\n```\n\n### useState vs ref - Critical Distinction\n\n```typescript\n\u002F\u002F CORRECT: Shared state (singleton pattern)\nexport const useAuth = () => {\n  const user = useState('auth-user', () => null)  \u002F\u002F Shared!\n  return { user }\n}\n\n\u002F\u002F WRONG: Creates new instance every call!\nexport const useAuth = () => {\n  const user = ref(null)  \u002F\u002F Not shared!\n  return { user }\n}\n```\n\n**Rule**: Use `useState` for shared\u002Fglobal state. Use `ref` for local component state only.\n\n### Complete Authentication Composable\n\n```typescript\n\u002F\u002F composables\u002FuseAuth.ts\nexport const useAuth = () => {\n  const user = useState\u003CUser | null>('auth-user', () => null)\n  const isAuthenticated = computed(() => !!user.value)\n  const isLoading = useState('auth-loading', () => false)\n\n  const login = async (email: string, password: string) => {\n    isLoading.value = true\n    try {\n      const data = await $fetch('\u002Fapi\u002Fauth\u002Flogin', {\n        method: 'POST',\n        body: { email, password }\n      })\n      user.value = data.user\n      return { success: true }\n    } catch (error) {\n      return { success: false, error: error.message }\n    } finally {\n      isLoading.value = false\n    }\n  }\n\n  const logout = async () => {\n    await $fetch('\u002Fapi\u002Fauth\u002Flogout', { method: 'POST' })\n    user.value = null\n    navigateTo('\u002Flogin')\n  }\n\n  const checkSession = async () => {\n    if (import.meta.server) return  \u002F\u002F Skip on server\n    try {\n      const data = await $fetch('\u002Fapi\u002Fauth\u002Fsession')\n      user.value = data.user\n    } catch {\n      user.value = null\n    }\n  }\n\n  return { user, isAuthenticated, isLoading, login, logout, checkSession }\n}\n```\n\n### SSR-Safe Browser APIs\n\n```typescript\n\u002F\u002F composables\u002FuseLocalStorage.ts\nexport const useLocalStorage = \u003CT>(key: string, defaultValue: T) => {\n  const data = useState\u003CT>(key, () => defaultValue)\n\n  \u002F\u002F Only access localStorage on client\n  if (import.meta.client) {\n    const stored = localStorage.getItem(key)\n    if (stored) {\n      data.value = JSON.parse(stored)\n    }\n\n    \u002F\u002F Watch and persist changes\n    watch(data, (newValue) => {\n      localStorage.setItem(key, JSON.stringify(newValue))\n    }, { deep: true })\n  }\n\n  return data\n}\n```\n\n## Data Fetching\n\n### useFetch - Basic Usage\n\n```typescript\n\u002F\u002F Simple GET request\nconst { data, error, pending, refresh } = await useFetch('\u002Fapi\u002Fusers')\n\n\u002F\u002F With options\nconst { data: users } = await useFetch('\u002Fapi\u002Fusers', {\n  method: 'GET',\n  query: { limit: 10, offset: 0 },\n  headers: { 'X-Custom-Header': 'value' }\n})\n```\n\n### Reactive Parameters\n\n```vue\n\u003Cscript setup lang=\"ts\">\nconst page = ref(1)\nconst search = ref('')\n\n\u002F\u002F Auto-refetches when page or search changes\nconst { data: users, pending } = await useFetch('\u002Fapi\u002Fusers', {\n  query: {\n    page,\n    search,\n    limit: 10\n  }\n})\n\n\u002F\u002F Or with computed\nconst query = computed(() => ({\n  page: page.value,\n  search: search.value,\n  limit: 10\n}))\n\nconst { data } = await useFetch('\u002Fapi\u002Fusers', { query })\n\u003C\u002Fscript>\n```\n\n### Transform Data\n\n```typescript\nconst { data: userNames } = await useFetch('\u002Fapi\u002Fusers', {\n  transform: (users) => users.map(u => u.name)\n})\n\n\u002F\u002F data.value is now string[] instead of User[]\n```\n\n### Pick Specific Fields\n\n```typescript\nconst { data } = await useFetch('\u002Fapi\u002Fuser', {\n  pick: ['id', 'name', 'email']  \u002F\u002F Only these fields in payload\n})\n```\n\n### useAsyncData - Custom Logic\n\n```typescript\n\u002F\u002F Multiple parallel requests\nconst { data } = await useAsyncData('dashboard', async () => {\n  const [users, posts, stats] = await Promise.all([\n    $fetch('\u002Fapi\u002Fusers'),\n    $fetch('\u002Fapi\u002Fposts'),\n    $fetch('\u002Fapi\u002Fstats')\n  ])\n  return { users, posts, stats }\n})\n\n\u002F\u002F Access: data.value.users, data.value.posts, data.value.stats\n```\n\n### Error Handling\n\n```typescript\nconst { data, error, status } = await useFetch('\u002Fapi\u002Fusers')\n\n\u002F\u002F Check error\nif (error.value) {\n  console.error('Error:', error.value.message)\n  console.error('Status:', error.value.statusCode)\n}\n\n\u002F\u002F Status values: 'idle' | 'pending' | 'success' | 'error'\nif (status.value === 'error') {\n  showError(error.value)\n}\n```\n\n### Manual Refresh\n\n```typescript\nconst { data, refresh, execute } = await useFetch('\u002Fapi\u002Fusers', {\n  immediate: false  \u002F\u002F Don't fetch on mount\n})\n\n\u002F\u002F Fetch manually\nawait execute()\n\n\u002F\u002F Refresh (re-fetch)\nawait refresh()\n\n\u002F\u002F Refresh with new params\nawait refresh({ dedupe: true })\n```\n\n### Shallow vs Deep Reactivity (v4 Change)\n\n```typescript\n\u002F\u002F Nuxt 4 default: Shallow reactivity\nconst { data } = await useFetch('\u002Fapi\u002Fuser')\ndata.value.name = 'New Name'  \u002F\u002F Won't trigger reactivity!\n\n\u002F\u002F Enable deep reactivity for mutations\nconst { data } = await useFetch('\u002Fapi\u002Fuser', {\n  deep: true\n})\ndata.value.name = 'New Name'  \u002F\u002F Now works!\n\n\u002F\u002F Or refresh instead of mutating\nconst { data, refresh } = await useFetch('\u002Fapi\u002Fuser')\nawait $fetch('\u002Fapi\u002Fuser', { method: 'PATCH', body: { name: 'New Name' } })\nawait refresh()  \u002F\u002F Re-fetch updated data\n```\n\n### Caching and Deduplication\n\n```typescript\nconst { data } = await useFetch('\u002Fapi\u002Fusers', {\n  key: 'users-list',           \u002F\u002F Custom cache key\n  dedupe: 'cancel',            \u002F\u002F Cancel duplicate requests\n  getCachedData: (key, nuxtApp) => {\n    \u002F\u002F Return cached data if valid\n    return nuxtApp.payload.data[key]\n  }\n})\n```\n\n### Lazy Loading Data\n\n```typescript\n\u002F\u002F useLazyFetch - Navigation happens immediately, data loads in background\nconst { data, pending } = useLazyFetch('\u002Fapi\u002Fusers')\n\n\u002F\u002F useLazyAsyncData\nconst { data, pending } = useLazyAsyncData('users', () => $fetch('\u002Fapi\u002Fusers'))\n```\n\n### $fetch - Client-Side Only\n\n```typescript\n\u002F\u002F In event handlers (not during SSR)\nconst submitForm = async () => {\n  const result = await $fetch('\u002Fapi\u002Fsubmit', {\n    method: 'POST',\n    body: formData.value\n  })\n}\n\n\u002F\u002F In server routes\nexport default defineEventHandler(async (event) => {\n  const externalData = await $fetch('https:\u002F\u002Fapi.example.com\u002Fdata')\n  return externalData\n})\n```\n\n## State Management\n\n### useState Patterns\n\n```typescript\n\u002F\u002F Simple counter\nconst count = useState('count', () => 0)\n\n\u002F\u002F Complex object\nconst settings = useState('settings', () => ({\n  theme: 'light',\n  notifications: true,\n  language: 'en'\n}))\n\n\u002F\u002F Typed state\ninterface User {\n  id: string\n  name: string\n  email: string\n}\nconst user = useState\u003CUser | null>('user', () => null)\n```\n\n### Shared Cart Example\n\n```typescript\n\u002F\u002F composables\u002FuseCart.ts\ninterface CartItem {\n  id: string\n  name: string\n  price: number\n  quantity: number\n}\n\nexport const useCart = () => {\n  const items = useState\u003CCartItem[]>('cart-items', () => [])\n\n  const total = computed(() =>\n    items.value.reduce((sum, item) => sum + item.price * item.quantity, 0)\n  )\n\n  const itemCount = computed(() =>\n    items.value.reduce((sum, item) => sum + item.quantity, 0)\n  )\n\n  const addItem = (product: Omit\u003CCartItem, 'quantity'>) => {\n    const existing = items.value.find(i => i.id === product.id)\n    if (existing) {\n      existing.quantity++\n    } else {\n      items.value.push({ ...product, quantity: 1 })\n    }\n  }\n\n  const removeItem = (id: string) => {\n    items.value = items.value.filter(i => i.id !== id)\n  }\n\n  const updateQuantity = (id: string, quantity: number) => {\n    const item = items.value.find(i => i.id === id)\n    if (item) {\n      item.quantity = Math.max(0, quantity)\n      if (item.quantity === 0) removeItem(id)\n    }\n  }\n\n  const clearCart = () => {\n    items.value = []\n  }\n\n  return { items, total, itemCount, addItem, removeItem, updateQuantity, clearCart }\n}\n```\n\n### Pinia Integration\n\n```bash\nbun add pinia @pinia\u002Fnuxt\n```\n\n```typescript\n\u002F\u002F nuxt.config.ts\nexport default defineNuxtConfig({\n  modules: ['@pinia\u002Fnuxt']\n})\n\n\u002F\u002F stores\u002Fauth.ts\nimport { defineStore } from 'pinia'\n\nexport const useAuthStore = defineStore('auth', {\n  state: () => ({\n    user: null as User | null,\n    token: null as string | null\n  }),\n\n  getters: {\n    isAuthenticated: (state) => !!state.user,\n    userName: (state) => state.user?.name ?? 'Guest'\n  },\n\n  actions: {\n    async login(email: string, password: string) {\n      const { user, token } = await $fetch('\u002Fapi\u002Fauth\u002Flogin', {\n        method: 'POST',\n        body: { email, password }\n      })\n      this.user = user\n      this.token = token\n    },\n\n    logout() {\n      this.user = null\n      this.token = null\n    }\n  }\n})\n\n\u002F\u002F Usage in components\nconst authStore = useAuthStore()\nawait authStore.login('user@example.com', 'password')\nconsole.log(authStore.userName)\n```\n\n## Common Anti-Patterns\n\n### Using ref Instead of useState\n\n```typescript\n\u002F\u002F WRONG - Creates new instance every time!\nexport const useAuth = () => {\n  const user = ref(null)  \u002F\u002F Not shared\n  return { user }\n}\n\n\u002F\u002F CORRECT\nexport const useAuth = () => {\n  const user = useState('auth-user', () => null)\n  return { user }\n}\n```\n\n### Missing Error Handling\n\n```typescript\n\u002F\u002F WRONG\nconst { data } = await useFetch('\u002Fapi\u002Fusers')\nconsole.log(data.value.length)  \u002F\u002F Crashes if error!\n\n\u002F\u002F CORRECT\nconst { data, error } = await useFetch('\u002Fapi\u002Fusers')\nif (error.value) {\n  showToast({ type: 'error', message: error.value.message })\n  return\n}\nconsole.log(data.value.length)\n```\n\n### Non-Deterministic Transform\n\n```typescript\n\u002F\u002F WRONG - Causes hydration mismatch!\nconst { data } = await useFetch('\u002Fapi\u002Fusers', {\n  transform: (users) => users.sort(() => Math.random() - 0.5)\n})\n\n\u002F\u002F CORRECT\nconst { data } = await useFetch('\u002Fapi\u002Fusers', {\n  transform: (users) => users.sort((a, b) => a.name.localeCompare(b.name))\n})\n```\n\n### Mutating Shallow Refs\n\n```typescript\n\u002F\u002F WRONG - v4 uses shallow refs by default\nconst { data } = await useFetch('\u002Fapi\u002Fuser')\ndata.value.name = 'New Name'  \u002F\u002F Won't trigger reactivity!\n\n\u002F\u002F CORRECT - Option 1: Enable deep\nconst { data } = await useFetch('\u002Fapi\u002Fuser', { deep: true })\ndata.value.name = 'New Name'\n\n\u002F\u002F CORRECT - Option 2: Replace entire value\ndata.value = { ...data.value, name: 'New Name' }\n\n\u002F\u002F CORRECT - Option 3: Refresh after mutation\nawait $fetch('\u002Fapi\u002Fuser', { method: 'PATCH', body: { name: 'New Name' } })\nawait refresh()\n```\n\n## Troubleshooting\n\n**Data Not Refreshing When Params Change:**\n- Ensure params are reactive: `{ query: { page } }` where `page = ref(1)`\n- Check you're using the ref itself, not `.value`\n\n**Hydration Mismatch with useState:**\n- Ensure key is unique: `useState('unique-key', () => value)`\n- Avoid `Math.random()` or `Date.now()` in initial values\n\n**State Lost on Navigation:**\n- Use `useState` instead of `ref` for persistent state\n- Check you're using the same key across components\n\n**Infinite Refetch Loop:**\n- Check for reactive dependencies in transform function\n- Use `watch` with `{ immediate: false }` for side effects\n\n## Related Skills\n\n- **nuxt-core**: Project setup, routing, configuration\n- **nuxt-server**: Server routes, API patterns\n- **nuxt-production**: Performance, testing, deployment\n\n---\n\n**Version**: 4.0.0 | **Last Updated**: 2025-12-28 | **License**: MIT\n","# Nuxt 4 Data Management\n\nComposables, data fetching, and state management patterns for Nuxt 4 applications.\n\n## Quick Reference\n\n### Data Fetching Methods\n\n| Method | Use Case | SSR | Caching | Reactive |\n|--------|----------|-----|---------|----------|\n| `useFetch` | Simple API calls | Yes | Yes | Yes |\n| `useAsyncData` | Custom async logic | Yes | Yes | Yes |\n| `$fetch` | Client-side only, events | No | No | No |\n\n### Composable Naming\n\n| Prefix | Purpose | Example |\n|--------|---------|---------|\n| `use` | State\u002Flogic composable | `useAuth`, `useCart` |\n| `fetch` | Data fetching only | `fetchUsers` (rare) |\n\n## When to Load References\n\n**Load `references\u002Fcomposables.md` when:**\n- Writing custom composables with complex state\n- Debugging state management issues or memory leaks\n- Implementing SSR-safe patterns with browser APIs\n- Building authentication or complex state composables\n- Understanding singleton vs per-call composable patterns\n\n**Load `references\u002Fdata-fetching.md` when:**\n- Implementing API data fetching with reactive parameters\n- Troubleshooting shallow vs deep reactivity issues\n- Debugging data not refreshing when params change\n- Implementing pagination, infinite scroll, or search\n- Understanding transform functions, caching, or error handling\n\n**Load `references\u002Fpinia-integration.md` when:**\n- Setting up Pinia for complex state management\n- Creating stores with getters and actions\n- Integrating Pinia with SSR\n- Persisting state across page reloads\n\n## Composables\n\n### useState - The Foundation\n\n`useState` creates SSR-safe, shared reactive state that persists across component instances.\n\n```typescript\n\u002F\u002F composables\u002FuseCounter.ts\nexport const useCounter = () => {\n  \u002F\u002F Singleton - shared across all components\n  const count = useState('counter', () => 0)\n\n  const increment = () => count.value++\n  const decrement = () => count.value--\n  const reset = () => count.value = 0\n\n  return { count, increment, decrement, reset }\n}\n```\n\n### useState vs ref - Critical Distinction\n\n```typescript\n\u002F\u002F CORRECT: Shared state (singleton pattern)\nexport const useAuth = () => {\n  const user = useState('auth-user', () => null)  \u002F\u002F Shared!\n  return { user }\n}\n\n\u002F\u002F WRONG: Creates new instance every call!\nexport const useAuth = () => {\n  const user = ref(null)  \u002F\u002F Not shared!\n  return { user }\n}\n```\n\n**Rule**: Use `useState` for shared\u002Fglobal state. Use `ref` for local component state only.\n\n### Complete Authentication Composable\n\n```typescript\n\u002F\u002F composables\u002FuseAuth.ts\nexport const useAuth = () => {\n  const user = useState\u003CUser | null>('auth-user', () => null)\n  const isAuthenticated = computed(() => !!user.value)\n  const isLoading = useState('auth-loading', () => false)\n\n  const login = async (email: string, password: string) => {\n    isLoading.value = true\n    try {\n      const data = await $fetch('\u002Fapi\u002Fauth\u002Flogin', {\n        method: 'POST',\n        body: { email, password }\n      })\n      user.value = data.user\n      return { success: true }\n    } catch (error) {\n      return { success: false, error: error.message }\n    } finally {\n      isLoading.value = false\n    }\n  }\n\n  const logout = async () => {\n    await $fetch('\u002Fapi\u002Fauth\u002Flogout', { method: 'POST' })\n    user.value = null\n    navigateTo('\u002Flogin')\n  }\n\n  const checkSession = async () => {\n    if (import.meta.server) return  \u002F\u002F Skip on server\n    try {\n      const data = await $fetch('\u002Fapi\u002Fauth\u002Fsession')\n      user.value = data.user\n    } catch {\n      user.value = null\n    }\n  }\n\n  return { user, isAuthenticated, isLoading, login, logout, checkSession }\n}\n```\n\n### SSR-Safe Browser APIs\n\n```typescript\n\u002F\u002F composables\u002FuseLocalStorage.ts\nexport const useLocalStorage = \u003CT>(key: string, defaultValue: T) => {\n  const data = useState\u003CT>(key, () => defaultValue)\n\n  \u002F\u002F Only access localStorage on client\n  if (import.meta.client) {\n    const stored = localStorage.getItem(key)\n    if (stored) {\n      data.value = JSON.parse(stored)\n    }\n\n    \u002F\u002F Watch and persist changes\n    watch(data, (newValue) => {\n      localStorage.setItem(key, JSON.stringify(newValue))\n    }, { deep: true })\n  }\n\n  return data\n}\n```\n\n## Data Fetching\n\n### useFetch - Basic Usage\n\n```typescript\n\u002F\u002F Simple GET request\nconst { data, error, pending, refresh } = await useFetch('\u002Fapi\u002Fusers')\n\n\u002F\u002F With options\nconst { data: users } = await useFetch('\u002Fapi\u002Fusers', {\n  method: 'GET',\n  query: { limit: 10, offset: 0 },\n  headers: { 'X-Custom-Header': 'value' }\n})\n```\n\n### Reactive Parameters\n\n```vue\n\u003Cscript setup lang=\"ts\">\nconst page = ref(1)\nconst search = ref('')\n\n\u002F\u002F Auto-refetches when page or search changes\nconst { data: users, pending } = await useFetch('\u002Fapi\u002Fusers', {\n  query: {\n    page,\n    search,\n    limit: 10\n  }\n})\n\n\u002F\u002F Or with computed\nconst query = computed(() => ({\n  page: page.value,\n  search: search.value,\n  limit: 10\n}))\n\nconst { data } = await useFetch('\u002Fapi\u002Fusers', { query })\n\u003C\u002Fscript>\n```\n\n### Transform Data\n\n```typescript\nconst { data: userNames } = await useFetch('\u002Fapi\u002Fusers', {\n  transform: (users) => users.map(u => u.name)\n})\n\n\u002F\u002F data.value is now string[] instead of User[]\n```\n\n### Pick Specific Fields\n\n```typescript\nconst { data } = await useFetch('\u002Fapi\u002Fuser', {\n  pick: ['id', 'name', 'email']  \u002F\u002F Only these fields in payload\n})\n```\n\n### useAsyncData - Custom Logic\n\n```typescript\n\u002F\u002F Multiple parallel requests\nconst { data } = await useAsyncData('dashboard', async () => {\n  const [users, posts, stats] = await Promise.all([\n    $fetch('\u002Fapi\u002Fusers'),\n    $fetch('\u002Fapi\u002Fposts'),\n    $fetch('\u002Fapi\u002Fstats')\n  ])\n  return { users, posts, stats }\n})\n\n\u002F\u002F Access: data.value.users, data.value.posts, data.value.stats\n```\n\n### Error Handling\n\n```typescript\nconst { data, error, status } = await useFetch('\u002Fapi\u002Fusers')\n\n\u002F\u002F Check error\nif (error.value) {\n  console.error('Error:', error.value.message)\n  console.error('Status:', error.value.statusCode)\n}\n\n\u002F\u002F Status values: 'idle' | 'pending' | 'success' | 'error'\nif (status.value === 'error') {\n  showError(error.value)\n}\n```\n\n### Manual Refresh\n\n```typescript\nconst { data, refresh, execute } = await useFetch('\u002Fapi\u002Fusers', {\n  immediate: false  \u002F\u002F Don't fetch on mount\n})\n\n\u002F\u002F Fetch manually\nawait execute()\n\n\u002F\u002F Refresh (re-fetch)\nawait refresh()\n\n\u002F\u002F Refresh with new params\nawait refresh({ dedupe: true })\n```\n\n### Shallow vs Deep Reactivity (v4 Change)\n\n```typescript\n\u002F\u002F Nuxt 4 default: Shallow reactivity\nconst { data } = await useFetch('\u002Fapi\u002Fuser')\ndata.value.name = 'New Name'  \u002F\u002F Won't trigger reactivity!\n\n\u002F\u002F Enable deep reactivity for mutations\nconst { data } = await useFetch('\u002Fapi\u002Fuser', {\n  deep: true\n})\ndata.value.name = 'New Name'  \u002F\u002F Now works!\n\n\u002F\u002F Or refresh instead of mutating\nconst { data, refresh } = await useFetch('\u002Fapi\u002Fuser')\nawait $fetch('\u002Fapi\u002Fuser', { method: 'PATCH', body: { name: 'New Name' } })\nawait refresh()  \u002F\u002F Re-fetch updated data\n```\n\n### Caching and Deduplication\n\n```typescript\nconst { data } = await useFetch('\u002Fapi\u002Fusers', {\n  key: 'users-list',           \u002F\u002F Custom cache key\n  dedupe: 'cancel',            \u002F\u002F Cancel duplicate requests\n  getCachedData: (key, nuxtApp) => {\n    \u002F\u002F Return cached data if valid\n    return nuxtApp.payload.data[key]\n  }\n})\n```\n\n### Lazy Loading Data\n\n```typescript\n\u002F\u002F useLazyFetch - Navigation happens immediately, data loads in background\nconst { data, pending } = useLazyFetch('\u002Fapi\u002Fusers')\n\n\u002F\u002F useLazyAsyncData\nconst { data, pending } = useLazyAsyncData('users', () => $fetch('\u002Fapi\u002Fusers'))\n```\n\n### $fetch - Client-Side Only\n\n```typescript\n\u002F\u002F In event handlers (not during SSR)\nconst submitForm = async () => {\n  const result = await $fetch('\u002Fapi\u002Fsubmit', {\n    method: 'POST',\n    body: formData.value\n  })\n}\n\n\u002F\u002F In server routes\nexport default defineEventHandler(async (event) => {\n  const externalData = await $fetch('https:\u002F\u002Fapi.example.com\u002Fdata')\n  return externalData\n})\n```\n\n## State Management\n\n### useState Patterns\n\n```typescript\n\u002F\u002F Simple counter\nconst count = useState('count', () => 0)\n\n\u002F\u002F Complex object\nconst settings = useState('settings', () => ({\n  theme: 'light',\n  notifications: true,\n  language: 'en'\n}))\n\n\u002F\u002F Typed state\ninterface User {\n  id: string\n  name: string\n  email: string\n}\nconst user = useState\u003CUser | null>('user', () => null)\n```\n\n### Shared Cart Example\n\n```typescript\n\u002F\u002F composables\u002FuseCart.ts\ninterface CartItem {\n  id: string\n  name: string\n  price: number\n  quantity: number\n}\n\nexport const useCart = () => {\n  const items = useState\u003CCartItem[]>('cart-items', () => [])\n\n  const total = computed(() =>\n    items.value.reduce((sum, item) => sum + item.price * item.quantity, 0)\n  )\n\n  const itemCount = computed(() =>\n    items.value.reduce((sum, item) => sum + item.quantity, 0)\n  )\n\n  const addItem = (product: Omit\u003CCartItem, 'quantity'>) => {\n    const existing = items.value.find(i => i.id === product.id)\n    if (existing) {\n      existing.quantity++\n    } else {\n      items.value.push({ ...product, quantity: 1 })\n    }\n  }\n\n  const removeItem = (id: string) => {\n    items.value = items.value.filter(i => i.id !== id)\n  }\n\n  const updateQuantity = (id: string, quantity: number) => {\n    const item = items.value.find(i => i.id === id)\n    if (item) {\n      item.quantity = Math.max(0, quantity)\n      if (item.quantity === 0) removeItem(id)\n    }\n  }\n\n  const clearCart = () => {\n    items.value = []\n  }\n\n  return { items, total, itemCount, addItem, removeItem, updateQuantity, clearCart }\n}\n```\n\n### Pinia Integration\n\n```bash\nbun add pinia @pinia\u002Fnuxt\n```\n\n```typescript\n\u002F\u002F nuxt.config.ts\nexport default defineNuxtConfig({\n  modules: ['@pinia\u002Fnuxt']\n})\n\n\u002F\u002F stores\u002Fauth.ts\nimport { defineStore } from 'pinia'\n\nexport const useAuthStore = defineStore('auth', {\n  state: () => ({\n    user: null as User | null,\n    token: null as string | null\n  }),\n\n  getters: {\n    isAuthenticated: (state) => !!state.user,\n    userName: (state) => state.user?.name ?? 'Guest'\n  },\n\n  actions: {\n    async login(email: string, password: string) {\n      const { user, token } = await $fetch('\u002Fapi\u002Fauth\u002Flogin', {\n        method: 'POST',\n        body: { email, password }\n      })\n      this.user = user\n      this.token = token\n    },\n\n    logout() {\n      this.user = null\n      this.token = null\n    }\n  }\n})\n\n\u002F\u002F Usage in components\nconst authStore = useAuthStore()\nawait authStore.login('user@example.com', 'password')\nconsole.log(authStore.userName)\n```\n\n## Common Anti-Patterns\n\n### Using ref Instead of useState\n\n```typescript\n\u002F\u002F WRONG - Creates new instance every time!\nexport const useAuth = () => {\n  const user = ref(null)  \u002F\u002F Not shared\n  return { user }\n}\n\n\u002F\u002F CORRECT\nexport const useAuth = () => {\n  const user = useState('auth-user', () => null)\n  return { user }\n}\n```\n\n### Missing Error Handling\n\n```typescript\n\u002F\u002F WRONG\nconst { data } = await useFetch('\u002Fapi\u002Fusers')\nconsole.log(data.value.length)  \u002F\u002F Crashes if error!\n\n\u002F\u002F CORRECT\nconst { data, error } = await useFetch('\u002Fapi\u002Fusers')\nif (error.value) {\n  showToast({ type: 'error', message: error.value.message })\n  return\n}\nconsole.log(data.value.length)\n```\n\n### Non-Deterministic Transform\n\n```typescript\n\u002F\u002F WRONG - Causes hydration mismatch!\nconst { data } = await useFetch('\u002Fapi\u002Fusers', {\n  transform: (users) => users.sort(() => Math.random() - 0.5)\n})\n\n\u002F\u002F CORRECT\nconst { data } = await useFetch('\u002Fapi\u002Fusers', {\n  transform: (users) => users.sort((a, b) => a.name.localeCompare(b.name))\n})\n```\n\n### Mutating Shallow Refs\n\n```typescript\n\u002F\u002F WRONG - v4 uses shallow refs by default\nconst { data } = await useFetch('\u002Fapi\u002Fuser')\ndata.value.name = 'New Name'  \u002F\u002F Won't trigger reactivity!\n\n\u002F\u002F CORRECT - Option 1: Enable deep\nconst { data } = await useFetch('\u002Fapi\u002Fuser', { deep: true })\ndata.value.name = 'New Name'\n\n\u002F\u002F CORRECT - Option 2: Replace entire value\ndata.value = { ...data.value, name: 'New Name' }\n\n\u002F\u002F CORRECT - Option 3: Refresh after mutation\nawait $fetch('\u002Fapi\u002Fuser', { method: 'PATCH', body: { name: 'New Name' } })\nawait refresh()\n```\n\n## Troubleshooting\n\n**Data Not Refreshing When Params Change:**\n- Ensure params are reactive: `{ query: { page } }` where `page = ref(1)`\n- Check you're using the ref itself, not `.value`\n\n**Hydration Mismatch with useState:**\n- Ensure key is unique: `useState('unique-key', () => value)`\n- Avoid `Math.random()` or `Date.now()` in initial values\n\n**State Lost on Navigation:**\n- Use `useState` instead of `ref` for persistent state\n- Check you're using the same key across components\n\n**Infinite Refetch Loop:**\n- Check for reactive dependencies in transform function\n- Use `watch` with `{ immediate: false }` for side effects\n\n## Related Skills\n\n- **nuxt-core**: Project setup, routing, configuration\n- **nuxt-server**: Server routes, API patterns\n- **nuxt-production**: Performance, testing, deployment\n\n---\n\n**Version**: 4.0.0 | **Last Updated**: 2025-12-28 | **License**: MIT\n",{"name":5,"license":15,"metadata":24,"description":7},{"author":25,"version":26,"category":27,"keywords":28,"framework":46,"last-verified":47,"framework-version":48},"Claude Skills Maintainers","4.0.0","Framework",[29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45],"useFetch","useAsyncData","$fetch","useState","composables","Pinia","data fetching","state management","reactive","shallow reactivity","reactive keys","transform","pending","error","refresh","dedupe","caching","Nuxt",1766880000000,"4.x","main","c475fc64e94e803b50d14a791dfee8853fbb2c5c","integrations\u002Fclaude-skills-secondsky\u002Fplugins\u002Fnuxt-v4\u002Fskills\u002Fnuxt-data","https:\u002F\u002Fgithub.com\u002FElogic360\u002Fsoftware-factory","https:\u002F\u002Fgithub.com\u002FElogic360","2026-11-08 22:21:22",{"source":8,"skillName":5,"commands":56,"prompt":66,"zipAvailable":67},[57,60,63],{"tool":58,"command":59},"npx","npx skills add Elogic360\u002Fsoftware-factory --skill nuxt-data",{"tool":61,"command":62},"bunx","bunx skills add Elogic360\u002Fsoftware-factory --skill nuxt-data",{"tool":64,"command":65},"pnpm","pnpm dlx skills add Elogic360\u002Fsoftware-factory --skill nuxt-data","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FElogic360\u002Fsoftware-factory\u002Fblob\u002Fmain\u002Fintegrations\u002Fclaude-skills-secondsky\u002Fplugins\u002Fnuxt-v4\u002Fskills\u002Fnuxt-data\u002FSKILL.md",true,[69,75,79],{"path":70,"resourceType":71,"resourceTypeDesc":72,"sizeBytes":73,"sourceHtmlUrl":74},"references\u002Fcomposables.md","REFERENCE","参考文档",16360,"https:\u002F\u002Fgithub.com\u002FElogic360\u002Fsoftware-factory\u002Fblob\u002Fmain\u002Fintegrations\u002Fclaude-skills-secondsky\u002Fplugins\u002Fnuxt-v4\u002Fskills\u002Fnuxt-data\u002Freferences\u002Fcomposables.md",{"path":76,"resourceType":71,"resourceTypeDesc":72,"sizeBytes":77,"sourceHtmlUrl":78},"references\u002Fdata-fetching.md",16293,"https:\u002F\u002Fgithub.com\u002FElogic360\u002Fsoftware-factory\u002Fblob\u002Fmain\u002Fintegrations\u002Fclaude-skills-secondsky\u002Fplugins\u002Fnuxt-v4\u002Fskills\u002Fnuxt-data\u002Freferences\u002Fdata-fetching.md",{"path":80,"resourceType":81,"resourceTypeDesc":82,"sizeBytes":83,"sourceHtmlUrl":84},"templates\u002Fcomposables\u002FuseAuth.ts","SCRIPT","脚本",3111,"https:\u002F\u002Fgithub.com\u002FElogic360\u002Fsoftware-factory\u002Fblob\u002Fmain\u002Fintegrations\u002Fclaude-skills-secondsky\u002Fplugins\u002Fnuxt-v4\u002Fskills\u002Fnuxt-data\u002Ftemplates\u002Fcomposables\u002FuseAuth.ts",[86,94,101,108,115,122],{"skillNo":87,"name":88,"nameZh":6,"description":89,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":90,"licenseFileUrl":6,"sourceHtmlUrl":91,"categories":92,"keywords":93,"publishedAt":19},"01M79G206MT3J6S0GY3C45P2KV","vss-summarize-video","Use to summarize a recorded video via the LVS summarization microservice (HITL-gated) with a VLM fallback. Not for report generation or live RTSP captioning.","Apache-2.0","https:\u002F\u002Fgithub.com\u002FElogic360\u002Fsoftware-factory\u002Fblob\u002Fmain\u002Fskills\u002Fnvidia\u002Fvss-summarize-video\u002FSKILL.md",[],[],{"skillNo":95,"name":96,"nameZh":6,"description":97,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":90,"licenseFileUrl":6,"sourceHtmlUrl":98,"categories":99,"keywords":100,"publishedAt":19},"01M79G1WN63PGRE8CKD47WEBQ5","vss-setup-video-analytics-api","Use to deploy the vss-video-analytics-api REST service standalone (config-source, data-log bind, Elasticsearch, optional Kafka). Not for full warehouse deploy.","https:\u002F\u002Fgithub.com\u002FElogic360\u002Fsoftware-factory\u002Fblob\u002Fmain\u002Fskills\u002Fnvidia\u002Fvss-setup-video-analytics-api\u002FSKILL.md",[],[],{"skillNo":102,"name":103,"nameZh":6,"description":104,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":90,"licenseFileUrl":6,"sourceHtmlUrl":105,"categories":106,"keywords":107,"publishedAt":19},"01M79G1S9F7VY3EF6H53PRP5AN","vss-setup-behavior-analytics","Use to deploy the vss-behavior-analytics service standalone (entrypoint, config-source, optional calibration). Not for the full warehouse deploy.","https:\u002F\u002Fgithub.com\u002FElogic360\u002Fsoftware-factory\u002Fblob\u002Fmain\u002Fskills\u002Fnvidia\u002Fvss-setup-behavior-analytics\u002FSKILL.md",[],[],{"skillNo":109,"name":110,"nameZh":6,"description":111,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":90,"licenseFileUrl":6,"sourceHtmlUrl":112,"categories":113,"keywords":114,"publishedAt":19},"01M79G1N1S1Y27PFZPYMNK1MTQ","vss-search-archive","Use this skill to run top-level VSS fusion search on archived video, or to ingest video files \u002F RTSP streams for search. Do NOT use for ad-hoc visual Q&A (use vss-ask-video), live captioning (use vss-deploy-dense-captioning), or video summarization and reports (use vss-summarize-video).","https:\u002F\u002Fgithub.com\u002FElogic360\u002Fsoftware-factory\u002Fblob\u002Fmain\u002Fskills\u002Fnvidia\u002Fvss-search-archive\u002FSKILL.md",[],[],{"skillNo":116,"name":117,"nameZh":6,"description":118,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":90,"licenseFileUrl":6,"sourceHtmlUrl":119,"categories":120,"keywords":121,"publishedAt":19},"01M79G1H6WN0Q6C0VCAXCZX6B7","vss-query-analytics","Use this skill when reading video-analytics metrics, incidents, alerts, and sensor data via the VA-MCP server (port 9901). Not for live VLM or incident-range narrative reports.","https:\u002F\u002Fgithub.com\u002FElogic360\u002Fsoftware-factory\u002Fblob\u002Fmain\u002Fskills\u002Fnvidia\u002Fvss-query-analytics\u002FSKILL.md",[],[],{"skillNo":123,"name":124,"nameZh":6,"description":125,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":90,"licenseFileUrl":6,"sourceHtmlUrl":126,"categories":127,"keywords":128,"publishedAt":19},"01M79G1DYPNXQS7QHZ0AAF5FX5","vss-manage-video-io-storage","Use to call the VIOS REST API (sensor list, timelines, clip extraction, snapshots, add\u002Fdelete sensors and streams). Not for VLM inference or search.","https:\u002F\u002Fgithub.com\u002FElogic360\u002Fsoftware-factory\u002Fblob\u002Fmain\u002Fskills\u002Fnvidia\u002Fvss-manage-video-io-storage\u002FSKILL.md",[],[]]