Skip to content

Async patterns in composables ​

For data fetching composables, use watchEffect() to automatically track reactive dependencies and refetch when they change. Always expose loading and error state refs to enable proper UI feedback.

Example:

typescript
function useFetch<T>(url: MaybeRefOrGetter<string>) {
  const data = ref<T | null>(null)
  const error = ref<Error | null>(null)
  const isLoading = ref(false)

  watchEffect(async () => {
    // Reset state
    data.value = null
    error.value = null
    isLoading.value = true

    try {
      const response = await fetch(toValue(url))
      data.value = await response.json()
    } catch (e) {
      error.value = e as Error
    } finally {
      isLoading.value = false
    }
  })

  return { data, error, isLoading }
}

// Usage - auto-refetches when userId changes
const {
  data: user,
  error,
  isLoading,
} = useFetch(() => `/api/users/${userId.value}`)

The watchEffect() automatically tracks url as a dependency and re-runs whenever it changes.

Rule for AI agents ​

- ALWAYS expose `loading`/`error` refs from async composables; use `watchEffect` for reactive data fetching

Eslint rule ​

No ESLint rule available

Source ​