Data fetching

In Vue 3 (especially when using the Composition API), fetching data cleanly and reactively is simple once you understand the pattern.
Let’s go through it step-by-step using both fetch() and axios.


🌐 1. Where to Fetch Data?

Usually, you’ll fetch data inside the onMounted() lifecycle hook — this ensures:

  • The component is mounted in the DOM
  • You can safely update reactive state afterward
import { ref, onMounted } from 'vue'

🟢 2. Example using the Native fetch() API

✅ Example: Users.vue

<template>
  <div>
    <h2>👥 User List</h2>

    <p v-if="loading">Loading...</p>
    <p v-if="error" class="error">{{ error }}</p>

    <ul v-if="users.length">
      <li v-for="user in users" :key="user.id">
        {{ user.name }} ({{ user.email }})
      </li>
    </ul>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'

const users = ref([])
const loading = ref(true)
const error = ref(null)

onMounted(async () => {
  try {
    const res = await fetch('https://jsonplaceholder.typicode.com/users')
    if (!res.ok) throw new Error('Network response was not ok')

    users.value = await res.json()
  } catch (err) {
    error.value = err.message
  } finally {
    loading.value = false
  }
})
</script>

<style scoped>
.error {
  color: red;
}
</style>

🧠 Explanation:

  • ref() holds reactive data (users, loading, error)
  • onMounted() triggers the data fetch when the component loads
  • Errors and loading states are handled gracefully

🔵 3. Example using Axios

Axios provides a cleaner syntax and better error handling than fetch().
You can install it via:

npm install axios

✅ Example: Posts.vue

<template>
  <div>
    <h2>📰 Posts</h2>

    <button @click="loadPosts">Reload</button>

    <p v-if="loading">Loading...</p>
    <p v-if="error" class="error">{{ error }}</p>

    <ul v-if="posts.length">
      <li v-for="post in posts" :key="post.id">
        <strong>{{ post.title }}</strong><br>
        {{ post.body }}
      </li>
    </ul>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import axios from 'axios'

const posts = ref([])
const loading = ref(false)
const error = ref(null)

async function loadPosts() {
  loading.value = true
  error.value = null

  try {
    const res = await axios.get('https://jsonplaceholder.typicode.com/posts?_limit=5')
    posts.value = res.data
  } catch (err) {
    error.value = err.message || 'Failed to fetch posts'
  } finally {
    loading.value = false
  }
}

onMounted(loadPosts)
</script>

<style scoped>
.error {
  color: red;
}
</style>

🧠 Axios Features:

  • Automatically parses JSON
  • Throws clear errors
  • Supports interceptors and global configuration

🧩 4. Handling Data in a Centralized Way

For larger apps, you might:

  • Use Pinia or Vuex for global state management.
  • Create API service files for reusable HTTP calls.

Example API service (api/users.js)

import axios from 'axios'

const api = axios.create({
  baseURL: 'https://jsonplaceholder.typicode.com'
})

export async function getUsers() {
  const res = await api.get('/users')
  return res.data
}

Use it in your component:

import { ref, onMounted } from 'vue'
import { getUsers } from '../api/users'

const users = ref([])

onMounted(async () => {
  users.value = await getUsers()
})

🧠 5. Best Practices

TipDescription
✅ Use onMounted()Fetch data after DOM is ready
⚙️ Use ref() or reactive()Keep data reactive
💬 Handle loading & errorImprove UX
🌍 Use API modulesSeparate logic from components
🧹 Cancel old requestsWhen dealing with navigation or reactivity (Axios supports cancellation tokens)

⚡ 6. Bonus: Using async setup() (Vue 3.3+)

You can even make your setup() function async and await data directly!

✅ Example

<script setup async>
import axios from 'axios'
import { ref } from 'vue'

const posts = ref(await axios.get('https://jsonplaceholder.typicode.com/posts?_limit=3')
  .then(res => res.data))
</script>

<template>
  <div>
    <h3>Posts (Loaded in async setup)</h3>
    <ul>
      <li v-for="p in posts" :key="p.id">{{ p.title }}</li>
    </ul>
  </div>
</template>

🧠 Useful for SSR or when you want data ready before rendering.


🚀 Summary

MethodProsCons
fetch()Built-in, no dependencyMust handle JSON + errors manually
axiosClean API, better errors, interceptorsRequires install
async setup()Elegant, fewer hooksExperimental in older Vue versions

Leave a Reply