Receber por email
← Voltar para o catálogo

nuxt-data

| Nuxt 4 data management: composables, data fetching with useFetch/useAsyncData, 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.

178estrelas
Atualizado há 5 meses

Ver no GitHub ↗ Licença: MIT

Como adicionar

/plugin marketplace add secondsky/claude-skills

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/nuxt-data/svg)](https://www.skillteca.com.br/skills/nuxt-data)

Alerta por categoria

Receba novas skills de Design e Frontend toda segunda

1 email curto, só com as skills novas de Design e Frontend. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

Nuxt 4 Data Management

Composables, data fetching, and state management patterns for Nuxt 4 applications.

Quick Reference

Data Fetching Methods

| Method | Use Case | SSR | Caching | Reactive | |--------|----------|-----|---------|----------| | useFetch | Simple API calls | Yes | Yes | Yes | | useAsyncData | Custom async logic | Yes | Yes | Yes | | $fetch | Client-side only, events | No | No | No |

Composable Naming

| Prefix | Purpose | Example | |--------|---------|---------| | use | State/logic composable | useAuth, useCart | | fetch | Data fetching only | fetchUsers (rare) |

When to Load References

Load references/composables.md when:

  • Writing custom composables with complex state
  • Debugging state management issues or memory leaks
  • Implementing SSR-safe patterns with browser APIs
  • Building authentication or complex state composables
  • Understanding singleton vs per-call composable patterns

Load references/data-fetching.md when:

  • Implementing API data fetching with reactive parameters
  • Troubleshooting shallow vs deep reactivity issues
  • Debugging data not refreshing when params change
  • Implementing pagination, infinite scroll, or search
  • Understanding transform functions, caching, or error handling

Load references/pinia-integration.md when:

  • Setting up Pinia for complex state management
  • Creating stores with getters and actions
  • Integrating Pinia with SSR
  • Persisting state across page reloads

Composables

useState - The Foundation

useState creates SSR-safe, shared reactive state that persists across component instances.

// composables/useCounter.ts
export const useCounter = () => {
  // Singleton - shared across all components
  const count = useState('counter', () => 0)

  const increment = () => count.value++
  const decrement = () => count.value--
  const reset = () => count.value = 0

  return { count, increment, decrement, reset }
}

useState vs ref - Critical Distinction

// CORRECT: Shared state (singleton pattern)
export const useAuth = () => {
  const user = useState('auth-user', () => null)  // Shared!
  return { user }
}

// WRONG: Creates new instance every call!
export const useAuth = () => {
  const user = ref(null)  // Not shared!
  return { user }
}

Rule: Use useState for shared/global state. Use ref for local component state only.

Complete Authentication Composable

// composables/useAuth.ts
export const useAuth = () => {
  const user = useState<User | null>('auth-user', () => null)
  const isAuthenticated = computed(() => !!user.value)
  const isLoading = useState('auth-loading', () => false)

  const login = async (email: string, password: string) => {
    isLoading.value = true
    try {
      const data = await $fetch('/api/auth/login', {
        method: 'POST',
        body: { email, password }
      })
      user.value = data.user
      return { success: true }
    } catch (error) {
      return { success: false, error: error.message }
    } finally {
      isLoading.value = false
    }
  }

  const logout = async () => {
    await $fetch('/api/auth/logout', { method: 'POST' })
    user.value = null
    navigateTo('/login')
  }

  const checkSession = async () => {
    if (import.meta.server) return  // Skip on server
    try {
      const data = await $fetch('/api/auth/session')
      user.value = data.user
    } catch {
      user.value = null
    }
  }

  return { user, isAuthenticated, isLoading, login, logout, checkSession }
}

SSR-Safe Browser APIs

// composables/useLocalStorage.ts
export const useLocalStorage = <T>(key: string, defaultValue: T) => {
  const data = useState<T>(key, () => defaultValue)

  // Only access localStorage on client
  if (import.meta.client) {
    const stored = localStorage.getItem(key)
    if (stored) {
      data.value = JSON.parse(stored)
    }

    // Watch and persist changes
    watch(data, (newValue) => {
      localStorage.setItem(key, JSON.stringify(newValue))
    }, { deep: true })
  }

  return data
}

Data Fetching

useFetch - Basic Usage

// Simple GET request
const { data, error, pending, refresh } = await useFetch('/api/users')

// With options
const { data: users } = await useFetch('/api/users', {
  method: 'GET',
  query: { limit: 10, offset: 0 },
  headers: { 'X-Custom-Header': 'value' }
})

Reactive Parameters

<script setup lang="ts">
const page = ref(1)
const search = ref('')

// Auto-refetches when page or search changes
const { data: users, pending } = await useFetch('/api/users', {
  query: {
    page,
    search,
    limit: 10
  }
})

// Or with computed
const query = computed(() => ({
  page: page.value,
  search: search.value,
  limit: 10
}))

const { data } = await useFetch('/api/users', { query })
</script>

Transform Data

const { data: userNames } = await useFetch('/api/users', {
  transform: (users) => users.map(u => u.name)
})

// data.value is now string[] instead of User[]

Pick Specific Fields

const { data } = await useFetch('/api/user', {
  pick: ['id', 'name', 'email']  // Only these fields in payload
})

useAsyncData - Custom Logic

// Multiple parallel requests
const { data } = await useAsyncData('dashboard', async () => {
  const [users, posts, stats] = await Promise.all([
    $fetch('/api/users'),
    $fetch('/api/posts'),
    $fetch('/api/stats')
  ])
  return { users, posts, stats }
})

// Access: data.value.users, data.value.posts, data.value.stats

Error Handling

const { data, error, status } = await useFetch('/api/users')

// Check error
if (error.value) {
  console.error('Error:', error.value.message)
  console.error('Status:', error.value.statusCode)
}

// Status values: 'idle' | 'pending' | 'success' | 'error'
if (status.value === 'error') {
  showError(error.value)
}

Manual Refresh

const { data, refresh, execute } = await useFetch('/api/users', {
  immediate: false  // Don't fetch on mount
})

// Fetch manually
await execute()

// Refresh (re-fetch)
await refresh()

// Refresh with new params
await refresh({ dedupe: true })

Shallow vs Deep Reactivity (v4 Change)

// Nuxt 4 default: Shallow reactivity
const { data } = await useFetch('/api/user')
data.value.name = 'New Name'  // Won't trigger reactivity!

// Enable deep reactivity for mutations
const { data } = await useFetch('/api/user', {
  deep: true
})
data.value.name = 'New Name'  // Now works!

// Or refresh instead of mutating
const { data, refresh } = await useFetch('/api/user')
await $fetch('/api/user', { method: 'PATCH', body: { name: 'New Name' } })
await refresh()  // Re-fetch updated data

Caching and Deduplication

const { data } = await useFetch('/api/users', {
  key: 'users-list',           // Custom cache key
  dedupe: 'cancel',            // Cancel duplicate requests
  getCachedData: (key, nuxtApp) => {
    // Return cached data if valid
    return nuxtApp.payload.data[key]
  }
})

Lazy Loading Data

// useLazyFetch - Navigation happens immediately, data loads in background
const { data, pending } = useLazyFetch('/api/users')

// useLazyAsyncData
const { data, pending } = useLazyAsyncData('users', () => $fetch('/api/users'))

$fetch - Client-Side Only

// In event handlers (not during SSR)
const submitForm = async () => {
  const result = await $fetch('/api/submit', {
    method: 'POST',
    body: formData.value
  })
}

// In server routes
export default defineEventHandler(async (event) => {
  const externalData = await $fetch('https://api.example.com/data')
  return externalData
})

State Management

useState Patterns

// Simple counter
const count = useState('count', () => 0)

// Complex object
const settings = useState('settings', () => ({
Compartilhar X LinkedIn