100+ animated React components (Aceternity UI) for Next.js with Tailwind. Use for hero sections, parallax, 3D effects, or encountering animation, shadcn CLI integration errors.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
| 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.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
설치 방법 보기설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.
Composables, data fetching, and state management patterns for Nuxt 4 applications.
| 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 |
| Prefix | Purpose | Example |
|---|---|---|
use | State/logic composable | useAuth, useCart |
fetch | Data fetching only | fetchUsers (rare) |
Load references/composables.md when:
Load references/data-fetching.md when:
Load references/pinia-integration.md when:
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 }
}
// 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.
// 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 }
}
// 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
}
// 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' }
})
<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>
const { data: userNames } = await useFetch('/api/users', {
transform: (users) => users.map(u => u.name)
})
// data.value is now string[] instead of User[]
const { data } = await useFetch('/api/user', {
pick: ['id', 'name', 'email'] // Only these fields in payload
})
// 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
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)
}
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 })
// 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
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]
}
})
// useLazyFetch - Navigation happens immediately, data loads in background
const { data, pending } = useLazyFetch('/api/users')
// useLazyAsyncData
const { data, pending } = useLazyAsyncData('users', () => $fetch('/api/users'))
// 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
})
// Simple counter
const count = useState('count', () => 0)
// Complex object
const settings = useState('settings', () => ({
theme: 'light',
notifications: true,
language: 'en'
}))
// Typed state
interface User {
id: string
name: string
email: string
}
const user = useState<User | null>('user', () => null)
// composables/useCart.ts
interface CartItem {
id: string
name: string
price: number
quantity: number
}
export const useCart = () => {
const items = useState<CartItem[]>('cart-items', () => [])
const total = computed(() =>
items.value.reduce((sum, item) => sum + item.price * item.quantity, 0)
)
const itemCount = computed(() =>
items.value.reduce((sum, item) => sum + item.quantity, 0)
)
const addItem = (product: Omit<CartItem, 'quantity'>) => {
const existing = items.value.find(i => i.id === product.id)
if (existing) {
existing.quantity++
} else {
items.value.push({ ...product, quantity: 1 })
}
}
const removeItem = (id: string) => {
items.value = items.value.filter(i => i.id !== id)
}
const updateQuantity = (id: string, quantity: number) => {
const item = items.value.find(i => i.id === id)
if (item) {
item.quantity = Math.max(0, quantity)
if (item.quantity === 0) removeItem(id)
}
}
const clearCart = () => {
items.value = []
}
return { items, total, itemCount, addItem, removeItem, updateQuantity, clearCart }
}
bun add pinia @pinia/nuxt
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@pinia/nuxt']
})
// stores/auth.ts
import { defineStore } from 'pinia'
export const useAuthStore = defineStore('auth', {
state: () => ({
user: null as User | null,
token: null as string | null
}),
getters: {
isAuthenticated: (state) => !!state.user,
userName: (state) => state.user?.name ?? 'Guest'
},
actions: {
async login(email: string, password: string) {
const { user, token } = await $fetch('/api/auth/login', {
method: 'POST',
body: { email, password }
})
this.user = user
this.token = token
},
logout() {
this.user = null
this.token = null
}
}
})
// Usage in components
const authStore = useAuthStore()
await authStore.login('user@example.com', 'password')
console.log(authStore.userName)
// WRONG - Creates new instance every time!
export const useAuth = () => {
const user = ref(null) // Not shared
return { user }
}
// CORRECT
export const useAuth = () => {
const user = useState('auth-user', () => null)
return { user }
}
// WRONG
const { data } = await useFetch('/api/users')
console.log(data.value.length) // Crashes if error!
// CORRECT
const { data, error } = await useFetch('/api/users')
if (error.value) {
showToast({ type: 'error', message: error.value.message })
return
}
console.log(data.value.length)
// WRONG - Causes hydration mismatch!
const { data } = await useFetch('/api/users', {
transform: (users) => users.sort(() => Math.random() - 0.5)
})
// CORRECT
const { data } = await useFetch('/api/users', {
transform: (users) => users.sort((a, b) => a.name.localeCompare(b.name))
})
// WRONG - v4 uses shallow refs by default
const { data } = await useFetch('/api/user')
data.value.name = 'New Name' // Won't trigger reactivity!
// CORRECT - Option 1: Enable deep
const { data } = await useFetch('/api/user', { deep: true })
data.value.name = 'New Name'
// CORRECT - Option 2: Replace entire value
data.value = { ...data.value, name: 'New Name' }
// CORRECT - Option 3: Refresh after mutation
await $fetch('/api/user', { method: 'PATCH', body: { name: 'New Name' } })
await refresh()
Data Not Refreshing When Params Change:
{ query: { page } } where page = ref(1).valueHydration Mismatch with useState:
useState('unique-key', () => value)Math.random() or Date.now() in initial valuesState Lost on Navigation:
useState instead of ref for persistent stateInfinite Refetch Loop:
watch with { immediate: false } for side effectsVersion: 4.0.0 | Last Updated: 2025-12-28 | License: MIT
아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.
로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.
아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.
100+ animated React components (Aceternity UI) for Next.js with Tailwind. Use for hero sections, parallax, 3D effects, or encountering animation, shadcn CLI integration errors.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Secure API authentication with JWT, OAuth 2.0, API keys. Use for authentication systems, third-party integrations, service-to-service communication, or encountering token management, security headers, auth flow errors.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Creates comprehensive API changelogs documenting breaking changes, deprecations, and migration strategies for API consumers. Use when managing API versions, communicating breaking changes, or creating upgrade guides.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Verifies API contracts between services using consumer-driven contracts, schema validation, and tools like Pact. Use when testing microservices communication, preventing breaking changes, or validating OpenAPI specifications.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Master REST and GraphQL API design principles to build intuitive, scalable, and maintainable APIs that delight developers. Use when designing new APIs, reviewing API specifications, or establishing API design standards.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Implements standardized API error responses with proper status codes, logging, and user-friendly messages. Use when building production APIs, implementing error recovery patterns, or integrating error monitoring services.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.