Get Data Into Your Components
HTTP — fetch & axios
Call APIs from onMounted, composables, or Pinia actions. Use the browser's fetch by default; reach for axios when you need interceptors and timeouts.
What you'll learn
- Fetch data inside onMounted
- Wrap requests in a composable
- Handle loading and error state
Vue has no built-in data layer — you call any HTTP library you like. The standards are the browser fetch for simple cases and axios when you want interceptors, request cancellation, or richer ergonomics.
fetch in onMounted
The simplest pattern: declare reactive state, fire the request in onMounted, store the result.
<script setup lang="ts">
import { ref, onMounted } from 'vue'
interface User { id: number; name: string }
const users = ref<User[]>([])
const loading = ref(false)
const error = ref<string | null>(null)
onMounted(async () => {
loading.value = true
try {
const res = await fetch('/api/users')
if (!res.ok) throw new Error(`HTTP ${res.status}`)
users.value = await res.json()
} catch (e: any) {
error.value = e.message
} finally {
loading.value = false
}
})
</script>
<template>
<p v-if="loading">Loading…</p>
<p v-else-if="error">Error: {{ error }}</p>
<ul v-else>
<li v-for="u in users" :key="u.id">{{ u.name }}</li>
</ul>
</template> axios
Axios sets timeouts, parses JSON, and supports interceptors out of the box.
import axios from 'axios'
const api = axios.create({ baseURL: '/api', timeout: 5000 })
api.interceptors.request.use(config => {
config.headers.Authorization = `Bearer ${getToken()}`
return config
})
const { data } = await api.get<User[]>('/users') Where Should Requests Live?
- One-off, component-local? Inline in
onMounted. - Reused across components? A composable.
- Shared, cached, or app-wide? A Pinia store action.