Comprehensive Vue 3 Tutorial: Project Setup, Option vs Composition API, and Custom Hooks

This tutorial walks through creating a Vue 3 project, explains key changes and the differences between Option API and Composition API, demonstrates useful CLI commands, and provides detailed examples of custom composable hooks such as useWindowSize, usePagination, and useFetch, along with best practices.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Comprehensive Vue 3 Tutorial: Project Setup, Option vs Composition API, and Custom Hooks

Vue 3 Project Initialization

Run the terminal command to create a new Vue 3 project, then open http://127.0.0.1:5173 to see the project running. The generated directory structure includes public, src, assets, components, stores, router, and views folders.

Important Files and Folders

public

: static assets that are not processed by the build tool; reference them with absolute paths like /favicon.ico. assets: images, CSS, etc. components: reusable UI components. stores: Pinia state management. router: Vue Router configuration. views: route components.

NPM Scripts

npm run dev

/ npx vite: start a development server with Hot Module Replacement. npm run build / npx vite build: bundle the project for production. npm run preview / npx vite preview --port 4173: preview the built dist folder locally.

Why Build?

Building performs syntax compilation, minification, third‑party module bundling, performance optimization, code protection, compatibility fixes, deployment convenience, gzip compression, and bundle analysis.

Option API vs. Composition API

Vue 3 offers both APIs. Option API follows the classic data, methods, computed, lifecycle sections, while Composition API groups logic by feature using reactive(), ref(), and <script setup>. Composition API improves readability for large components.

Option API Example

Logic is split into sections such as data, methods, etc.

Composition API Example

All logic can be placed inside <script setup> without a return statement.

Custom Composable Hooks

Reusable logic can be encapsulated in hooks: useWindowSize: tracks window width and height. usePagination: manages current page, builds paginated endpoint, provides nextPage and prevPage functions. useFetch: performs async fetch, exposes data, loading, and error refs, supports reactive endpoint changes.

import { ref, computed, onMounted, isRef, watch } from "vue";

export function usePagination(endpoint) {
  const currentPage = ref(1);
  const paginatedEndpoint = computed(() => `${endpoint}?page=${currentPage.value}`);
  function nextPage() { currentPage.value++; }
  function prevPage() { if (currentPage.value > 1) currentPage.value--; }
  return { endpoint: paginatedEndpoint, nextPage, prevPage };
}

export function useFetch(endpoint) {
  const data = ref(null);
  const loading = ref(true);
  const error = ref(null);
  function fetchData() {
    loading.value = true;
    return fetch(isRef(endpoint) ? endpoint.value : endpoint, {
      method: "get",
      headers: { "content-type": "application/json" }
    })
      .then(res => {
        if (!res.ok) {
          const err = new Error(res.statusText);
          err.json = res.json();
          throw err;
        }
        return res.json();
      })
      .then(json => { data.value = json; })
      .catch(err => { error.value = err; if (err.json) { err.json.then(json => { error.value.message = json.message; }); } })
      .finally(() => { loading.value = false; });
  }
  onMounted(() => { fetchData(); });
  if (isRef(endpoint)) {
    watch(endpoint, () => { fetchData(); });
  }
  return { data, loading, error };
}

Usage in a component:

<script setup>
import { usePagination, useFetch } from './hooks';
const endpoint = 'https://example.com/api';
const { endpoint: paginatedEndpoint, nextPage, prevPage } = usePagination(endpoint);
const { data, loading, error } = useFetch(paginatedEndpoint);
function handleNextPage() { nextPage(); }
function handlePrevPage() { prevPage(); }
</script>

<template>
  <div>
    <button @click="handlePrevPage">Prev</button>
    <button @click="handleNextPage">Next</button>
    <div v-if="loading">Loading...</div>
    <div v-if="data"><!-- display data --></div>
    <div v-if="error">Error: {{ error }}</div>
  </div>
</template>

Advanced Script Features

setup()

vs. <script setup> – the latter is syntactic sugar that removes the need for a return statement. defineProps and defineEmits – compiler macros for declaring props and events without imports.

Multiple <script> blocks can be merged during compilation. defineOptions (Vue 3.3+): declare component options directly inside <script setup>. defineExpose: expose internal methods or values to parent components. defineSlots (Vue 3.3+): provide IDE slot type hints. Suspense: handle async components with fallback UI.

Single File Components (SFC)

SFCs combine <template>, <script> (or <script setup>) and <style> sections in a single .vue file, which is compiled by @vue/compiler-sfc into JavaScript and CSS for the browser.

References

Vue Chinese official documentation and community resources.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Composition APIVue3Custom HooksOption API
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.