What Causes This Error?
This error occurs when you pass a value directly to useState instead of a function that returns the initial value.
The Problem
// ❌ Wrong - passing value directly
const count = useState('count', 0)
const user = useState('user', { name: 'John' })
const items = useState('items', [])
// ❌ Also wrong - passing result of function call
const data = useState('data', fetchData())
The Fix
// ✅ Correct - pass a function that returns the value
const count = useState('count', () => 0)
const user = useState('user', () => ({ name: 'John' }))
const items = useState('items', () => [])
// ✅ Correct - async initialization
const data = useState('data', () => null)
// Then fetch data separately
Why a Function?
Nuxt uses the function (called a “factory function”) because:
- SSR Safety - The function is called once per request on the server
- Lazy Initialization - Value is only computed when needed
- Fresh State - Each request gets fresh initial state
- Avoids Shared State - Prevents state leaking between requests
Common Patterns
Basic Types
// Numbers
const count = useState('count', () => 0)
// Strings
const name = useState('name', () => '')
// Booleans
const isOpen = useState('isOpen', () => false)
// Arrays
const items = useState('items', () => [])
// Objects
const user = useState('user', () => ({
name: '',
email: ''
}))
With TypeScript
// Typed state
const count = useState<number>('count', () => 0)
const user = useState<User | null>('user', () => null)
const items = useState<string[]>('items', () => [])
interface User {
id: number
name: string
}
const currentUser = useState<User>('currentUser', () => ({
id: 0,
name: ''
}))
Complex Initial Values
// Computed initial value
const config = useState('config', () => {
return {
theme: 'dark',
language: 'en',
notifications: true
}
})
// Based on runtime config
const apiUrl = useState('apiUrl', () => {
const config = useRuntimeConfig()
return config.public.apiBase
})
Nullable State
// State that starts as null
const user = useState<User | null>('user', () => null)
// Check before using
if (user.value) {
console.log(user.value.name)
}
useState Without Initial Value
If state might be set elsewhere, you can omit the init function:
// Just reading state (might be undefined)
const count = useState<number>('count')
// Setting state
count.value = 42
But it’s safer to always provide an initial value:
// Always provide default
const count = useState('count', () => 0)
Async Data with useState
Don’t fetch data inside useState. Use separate composables:
// ❌ Wrong - async in useState
const user = useState('user', async () => {
return await $fetch('/api/user') // This won't work as expected!
})
// ✅ Correct - separate concerns
const user = useState<User | null>('user', () => null)
// Fetch data with useAsyncData
const { data } = await useAsyncData('user', () => $fetch('/api/user'))
// Or in onMounted
onMounted(async () => {
user.value = await $fetch('/api/user')
})
Shared Composables with useState
// composables/useCounter.ts
export function useCounter() {
const count = useState('counter', () => 0)
function increment() {
count.value++
}
function decrement() {
count.value--
}
return {
count: readonly(count),
increment,
decrement
}
}
Common Mistakes
Mistake 1: Passing Variable
const initialValue = 0
// ❌ Wrong
const count = useState('count', initialValue)
// ✅ Correct
const count = useState('count', () => initialValue)
Mistake 2: Passing Function Result
function getDefault() {
return { name: 'John' }
}
// ❌ Wrong - passes the result
const user = useState('user', getDefault())
// ✅ Correct - passes the function
const user = useState('user', getDefault)
// or
const user = useState('user', () => getDefault())
Mistake 3: Arrow Function Without Parentheses for Object
// ❌ Wrong - arrow function body, not return
const user = useState('user', () => { name: 'John' })
// ✅ Correct - wrap object in parentheses
const user = useState('user', () => ({ name: 'John' }))
Quick Reference
| Usage | Valid? |
|---|---|
useState('key', 0) | ❌ No |
useState('key', () => 0) | ✅ Yes |
useState('key', []) | ❌ No |
useState('key', () => []) | ✅ Yes |
useState('key', {}) | ❌ No |
useState('key', () => ({})) | ✅ Yes |
useState('key', getValue()) | ❌ No |
useState('key', getValue) | ✅ Yes |
useState('key', () => getValue()) | ✅ Yes |