Home About Skills Products Work
Projects Services Experience
Learn
Tutorials Courses Blogs Resources
Contact
Blog · Vue.js

Vue 3 Composition API: A Practical Introduction

Vue 3 Composition API: A Practical Introduction

Vue 3's Composition API changed how you organize component logic — instead of scattering related state across data, computed, and methods, you group everything that belongs together in one place. Here's a practical introduction for developers coming from the Options API or another framework entirely.

Why the Composition API Exists

In a large Options API component, all the logic for one feature (say, a search filter) ends up spread across three separate blocks — some state in data(), a computed property in computed, a handler in methods. The Composition API lets you write all of that together as one cohesive, reusable function.

setup() and <script setup>

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

const count = ref(0);
const doubled = computed(() => count.value * 2);

function increment() {
  count.value++;
}
</script>

<template>
  <button @click="increment">Count: {{ count }} (doubled: {{ doubled }})</button>
</template>

<script setup> is the modern, recommended syntax — everything declared at the top level is automatically exposed to the template, no explicit return statement needed.

ref vs reactive

const count = ref(0);           // primitive — access/mutate via .value
const user = reactive({ name: 'Bikesh', role: 'Developer' }); // object — no .value needed

ref works for any value type (primitives included) and needs .value in JavaScript, but not in the template — Vue unwraps it automatically there. reactive only works on objects/arrays and never needs .value, but loses reactivity if you destructure it.

Composables: Reusable Logic

The real payoff of the Composition API is extracting logic into reusable "composables" — plain functions that use Vue's reactivity APIs:

// useCounter.js
import { ref } from 'vue';

export function useCounter(initial = 0) {
  const count = ref(initial);
  const increment = () => count.value++;
  const decrement = () => count.value--;
  return { count, increment, decrement };
}
<script setup>
import { useCounter } from './useCounter';
const { count, increment } = useCounter(10);
</script>

Any component can now share this exact logic — something the Options API had no clean equivalent for beyond mixins, which came with their own naming-collision problems.

Watching Reactive State

import { watch } from 'vue';

watch(count, (newVal, oldVal) => {
  console.log(`count changed from ${oldVal} to ${newVal}`);
});

The Composition API isn't a replacement that makes the Options API wrong — it's a better tool for components whose logic has grown past a handful of lines, which in a real app is most of them.

State Management in Vue with Pinia

State Management in Vue with Pinia

Why Pinia replaced Vuex as Vue's recommended state management library, and how to set up stores in both Options and Composition API styles.

Building a Full-Stack App with Vue.js and Laravel (Inertia.js)

Building a Full-Stack App with Vue.js and Laravel (Inertia.js)

How Inertia.js lets a Laravel backend and Vue.js frontend feel like one SPA-style codebase, without building a separate JSON API.

Esc