Vue 3 introduced the Composition API — a modern, function-based approach to building components. If you’ve been using the Options API (data, methods, computed, etc.), this might feel like a big shift. But the Composition API gives you more flexibility, reusability, and scalability.
In this post, we’ll explore what it is, how it works, why it matters, and we’ll finish with a real-world API fetching example.
🧩 What is the Composition API?
The Composition API is a collection of functions (like ref, reactive, watch, computed) that you use inside a setup() function (or <script setup>). Instead of organizing code into option blocks, you compose logic directly.
👉 In short:
It lets you group related logic together in one place, making your components more readable and reusable.
🔑 Core Features
Here are the most important building blocks:
ref()→ create reactive primitive values (like numbers, strings, booleans).reactive()→ create reactive objects or arrays.computed()→ define derived values based on reactive state.watch()→ run side effects when values change.- Lifecycle hooks (
onMounted,onUnmounted, etc.) → usable insidesetup(). - Composables → reusable functions built with Composition API logic.
⚖️ Options API vs Composition API
Options API (Vue 2 style)
<script>
export default {
data() {
return {
count: 0
}
},
methods: {
increment() {
this.count++
}
}
}
</script>
Composition API (Vue 3 style)
<script setup>
import { ref } from 'vue'
const count = ref(0)
const increment = () => count.value++
</script>
<template>
<p>{{ count }}</p>
<button @click="increment">+</button>
</template>
✨ Notice the difference:
- With Options API, logic is split across
dataandmethods. - With Composition API, everything (state + methods) is grouped together.
🚀 Why Use Composition API?
- Better logic organization → Group related logic in one place.
- Reusability → Extract shared code into composables (
useAuth,useFetch, etc.). - TypeScript-friendly → Works smoothly with static typing.
- Scalable → Easier to manage large and complex components.
🌍 Real-World Example: Fetching API Data
Let’s say we want to fetch user data from an API.
Step 1: Create a composable useFetch.js
// composables/useFetch.js
import { ref, onMounted } from 'vue'
export function useFetch(url) {
const data = ref(null)
const error = ref(null)
const loading = ref(true)
onMounted(async () => {
try {
const res = await fetch(url)
data.value = await res.json()
} catch (err) {
error.value = err
} finally {
loading.value = false
}
})
return { data, error, loading }
}
Step 2: Use it inside a component
<script setup>
import { useFetch } from '@/composables/useFetch'
const { data, error, loading } = useFetch('https://jsonplaceholder.typicode.com/users')
</script>
<template>
<div>
<p v-if="loading">Loading...</p>
<p v-if="error">Error: {{ error.message }}</p>
<ul v-if="data">
<li v-for="user in data" :key="user.id">{{ user.name }}</li>
</ul>
</div>
</template>
✨ What happened?
- The composable
useFetchhandles logic for fetching. - The component only takes care of rendering.
- Now, you can reuse
useFetchanywhere in your app.
🎯 Final Thoughts
The Composition API makes Vue components cleaner, reusable, and scalable. It might look different at first, but once you start grouping related logic together, you’ll see how powerful it is compared to the Options API.
If you’re building modern Vue 3 apps, learning the Composition API is a must.
🔄 Vue.js: Composition API vs Mixins vs Composables
When working with Vue, developers often ask:
- What’s the difference between the Composition API and Composables?
- Do Mixins still matter in Vue 3?
- When should I use one over the other?
Let’s break it down with clear explanations and examples.
🧩 Mixins (Vue 2 era)
🔑 What are Mixins?
Mixins are objects that contain reusable logic (data, methods, lifecycle hooks) which can be merged into components.
⚡ Example: Counter with a mixin
// mixins/counterMixin.js
export const counterMixin = {
data() {
return {
count: 0
}
},
methods: {
increment() {
this.count++
}
}
}
<script>
import { counterMixin } from '@/mixins/counterMixin'
export default {
mixins: [counterMixin]
}
</script>
<template>
<p>{{ count }}</p>
<button @click="increment">+</button>
</template>
✅ Pros
- Easy to reuse logic.
- Simple syntax.
❌ Cons
- Name conflicts → two mixins or component methods can override each other.
- Hard to track where logic comes from in large apps.
- Doesn’t scale well.
👉 That’s why Vue 3 encourages Composition API + Composables instead.
⚙️ Composition API
🔑 What is it?
The Composition API is a set of functions (ref, reactive, watch, computed, lifecycle hooks) that let you write components in a function-based style.
⚡ Example: Counter with Composition API
<script setup>
import { ref } from 'vue'
const count = ref(0)
const increment = () => count.value++
</script>
<template>
<p>{{ count }}</p>
<button @click="increment">+</button>
</template>
👉 Unlike Mixins, all logic lives inside the component — no magic merging.
✅ Pros
- Explicit and predictable.
- Works great with TypeScript.
- Organizes related logic together instead of scattering across options.
🔄 Composables
🔑 What are Composables?
Composables are just functions that use the Composition API to encapsulate and reuse logic.
They’re often named with a use prefix (useAuth, useCounter, useFetch).
⚡ Example: Reusable counter composable
// composables/useCounter.js
import { ref } from 'vue'
export function useCounter() {
const count = ref(0)
const increment = () => count.value++
return { count, increment }
}
Usage in a component:
<script setup>
import { useCounter } from '@/composables/useCounter'
const { count, increment } = useCounter()
</script>
<template>
<p>{{ count }}</p>
<button @click="increment">+</button>
</template>
✅ Pros
- Clear and explicit (unlike Mixins).
- Reusable across multiple components.
- Easy to test (plain functions).
- Scales beautifully in large apps.
🆚 Side-by-Side Comparison
| Feature | Mixins 🧩 | Composition API ⚙️ | Composables 🔄 |
|---|---|---|---|
| Introduced in | Vue 2 | Vue 3 | Vue 3 |
| Reusability | Yes, but limited | Mostly inside components | Yes, very flexible |
| Code Organization | Scattered across mixins | Grouped inside setup() | Encapsulated in functions |
| Conflicts | Possible (naming issues) | None | None |
| Testability | Harder | Good | Excellent |
| TypeScript Support | Poor | Strong | Strong |
| Recommended in Vue 3? | ❌ Not preferred | ✅ Yes | ✅ Yes |
🎯 Final Thoughts
- Mixins were useful in Vue 2, but they can cause naming conflicts and make code hard to trace.
- Composition API solves these issues by letting you organize logic in
setup()with functions likeref,reactive,watch. - Composables build on the Composition API — they’re just functions that encapsulate and reuse logic across components.
👉 In Vue 3, the recommended pattern is:
- Use Composition API inside components.
- Extract reusable logic into Composables.
- Avoid Mixins unless maintaining legacy Vue 2 code.