SyntaxStudy
Sign Up
Vue.js Fetching Data with the Fetch API in onMounted
Vue.js Beginner 1 min read

Fetching Data with the Fetch API in onMounted

The simplest way to load data from an API in a Vue component is inside `onMounted`. Because the DOM is available at this point and the component's reactive state is initialised, you can safely set data refs after the async operation completes. Always handle loading and error states explicitly so the UI never shows a blank page while the request is in flight. Pair `onMounted` data loading with a `watch` on any reactive parameters (such as a route param or a filter input) to re-fetch when those values change. This ensures the component always reflects the current URL without being destroyed and recreated. Cancel in-flight requests using `AbortController` inside the watcher's cleanup function to prevent race conditions. For server-side rendering with Nuxt or `@vue/server-renderer`, use `onServerPrefetch` to await data before the component is serialised. On the client, hydration will see the pre-filled state and skip a redundant network request.
Example
<template>
  <div>
    <p v-if="isLoading">Loading users…</p>
    <p v-else-if="error" class="error">Error: {{ error }}</p>
    <ul v-else>
      <li v-for="user in users" :key="user.id">
        {{ user.name }} — {{ user.email }}
      </li>
    </ul>
    <button @click="refresh" :disabled="isLoading">Refresh</button>
  </div>
</template>

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

const users     = ref([]);
const isLoading = ref(false);
const error     = ref(null);

async function fetchUsers() {
  isLoading.value = true;
  error.value     = null;
  try {
    const res = await fetch('https://jsonplaceholder.typicode.com/users');
    if (!res.ok) throw new Error(`HTTP ${res.status} — ${res.statusText}`);
    users.value = await res.json();
  } catch (e) {
    error.value = e.message;
  } finally {
    isLoading.value = false;
  }
}

const refresh = fetchUsers;

onMounted(fetchUsers);
</script>