How to Use Composition Api in Vue
Introduction The Composition API in Vue.js represents a modern approach to building Vue applications by allowing developers to organize and reuse code more efficiently. Introduced in Vue 3, the Composition API offers greater flexibility compared to the traditional Options API, enabling better logic abstraction, improved TypeScript integration, and easier code maintenance in complex projects. Under
Introduction
The Composition API in Vue.js represents a modern approach to building Vue applications by allowing developers to organize and reuse code more efficiently. Introduced in Vue 3, the Composition API offers greater flexibility compared to the traditional Options API, enabling better logic abstraction, improved TypeScript integration, and easier code maintenance in complex projects.
Understanding how to use the Composition API is essential for developers aiming to leverage Vue's full capabilities. This tutorial will provide a comprehensive, step-by-step guide on using the Composition API, discuss best practices, introduce useful tools and resources, demonstrate real-world examples, and answer frequently asked questions.
Step-by-Step Guide
1. Setting Up a Vue 3 Project
Before diving into the Composition API, ensure you have a Vue 3 project set up. You can create one quickly using Vue CLI or Vite.
Example using Vue CLI:
bash
npm install -g @vue/cli
vue create my-vue-app
Choose Vue 3 preset and complete the setup.
Alternatively, with Vite:
bash
npm create vite@latest my-vue-app -- --template vue
2. Understanding the Basics of Composition API
The Composition API centers around the setup() function, which acts as the entry point for composition logic inside Vue components.
Key concepts include:
- reactive(): Makes an object reactive.
- ref(): Creates a reactive primitive value.
- computed(): Defines computed properties based on reactive data.
- watch(): Watches reactive data and executes code on change.
3. Creating a Simple Component with Composition API
Example: Counter component that increments a number on button click.
Counter.vue
<script setup>
import { ref } from 'vue'
const count = ref(0)
function increment() {
count.value++
}
</script>
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</template>
Explanation:
ref(0)creates a reactive number initialized to 0.incrementfunction modifies the reactive value.- The template accesses
countdirectly, Vue unwraps refs in templates.
4. Using reactive() for Complex State
When managing objects or arrays, reactive() provides a more suitable reactive wrapper.
Example:
<script setup>
import { reactive } from 'vue'
const state = reactive({
name: 'Vue User',
age: 30
})
function updateName(newName) {
state.name = newName
}
</script>
<template>
<div>
<p>Name: {{ state.name }}</p>
<p>Age: {{ state.age }}</p>
<input v-model="state.name" placeholder="Enter name" />
</div>
</template>
5. Creating Computed Properties
Computed properties reactively depend on other reactive data and update automatically.
Example:
<script setup>
import { ref, computed } from 'vue'
const firstName = ref('John')
const lastName = ref('Doe')
const fullName = computed(() => ${firstName.value} ${lastName.value})
</script>
<template>
<div>
<input v-model="firstName" placeholder="First Name" />
<input v-model="lastName" placeholder="Last Name" />
<p>Full Name: {{ fullName }}</p>
</div>
</template>
6. Watching Reactive Data
The watch() function allows you to run side effects when reactive data changes.
Example:
<script setup>
import { ref, watch } from 'vue'
const searchTerm = ref('')
watch(searchTerm, (newVal, oldVal) => {
console.log(Search term changed from ${oldVal} to ${newVal})
})
</script>
<template>
<input v-model="searchTerm" placeholder="Search..." />
</template>
7. Organizing Code with Composables
Composables are reusable functions encapsulating composition logic.
Create a useCounter.js composable:
import { ref } from 'vue'
export function useCounter() {
const count = ref(0)
function increment() {
count.value++
}
return {
count,
increment
}
}
Use it inside a component:
<script setup>
import { useCounter } from './useCounter'
const { count, increment } = useCounter()
</script>
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</template>
Best Practices
1. Use ref for Primitives and reactive for Objects
For simple data types like numbers, strings, or booleans, use ref(). For complex objects and arrays, use reactive() to maintain reactivity and reduce boilerplate.
2. Prefer script setup Syntax
The <script setup> syntax is a compile-time syntax that simplifies the Composition API usage by reducing verbosity and improving readability.
3. Encapsulate Logic in Composables
Extract reusable logic into composable functions to keep components clean and maintainable. This practice encourages DRY (Don't Repeat Yourself) principles and better testability.
4. Avoid Overusing reactive() When Not Needed
Using reactive() unnecessarily can add complexity. If only a few properties need to be reactive, consider using multiple ref() variables instead.
5. Use toRefs() When Returning Reactive Objects
When exposing properties from a reactive object, use toRefs() to maintain reactivity in destructured assignments.
6. Leverage TypeScript Support
The Composition API works seamlessly with TypeScript, making it easier to type reactive state, props, and emitted events.
Tools and Resources
1. Official Vue.js Documentation
The authoritative source for learning the Composition API is the official Vue.js documentation. It provides in-depth explanations, examples, and API references.
2. Vue Devtools
Vue Devtools is a browser extension that helps inspect and debug Vue apps. It supports Vue 3 and the Composition API, making it easier to track reactive state changes.
3. Vite
Vite is a fast build tool optimized for Vue 3 projects. Using Vite ensures an efficient development experience with hot module replacement and fast compilation.
4. VueUse
VueUse is a collection of utility composables that simplify common tasks such as state management, event handling, and browser APIs.
5. TypeScript Playground
For TypeScript users, the TypeScript Playground allows you to experiment with types and interfaces in Vue components.
Real Examples
Example 1: Todo List Application
This example demonstrates managing a list of todos using the Composition API.
<script setup>
import { reactive, ref } from 'vue'
const state = reactive({
todos: [],
newTodo: ''
})
function addTodo() {
if (state.newTodo.trim()) {
state.todos.push({ text: state.newTodo, done: false })
state.newTodo = ''
}
}
function toggleDone(index) {
state.todos[index].done = !state.todos[index].done
}
</script>
<template>
<div>
<input v-model="state.newTodo" placeholder="Add new todo" @keyup.enter="addTodo" />
<button @click="addTodo">Add</button>
<ul>
<li v-for="(todo, index) in state.todos" :key="index">
<input type="checkbox" v-model="todo.done" @change="toggleDone(index)" />
<span :style="{ textDecoration: todo.done ? 'line-through' : 'none' }">{{ todo.text }}</span>
</li>
</ul>
</div>
</template>
Example 2: Fetching Data with watchEffect()
Using watchEffect() to automatically fetch data when a reactive dependency changes.
<script setup>
import { ref, watchEffect } from 'vue'
const userId = ref(1)
const userData = ref(null)
const loading = ref(false)
const error = ref(null)
watchEffect(async () => {
loading.value = true
error.value = null
try {
const response = await fetch(https://jsonplaceholder.typicode.com/users/${userId.value})
if (!response.ok) throw new Error('Network error')
userData.value = await response.json()
} catch (err) {
error.value = err.message
} finally {
loading.value = false
}
})
</script>
<template>
<div>
<input type="number" v-model.number="userId" min="1" max="10" />
<div v-if="loading">Loading...</div>
<div v-if="error">Error: {{ error }}</div>
<div v-if="userData">
<h3>{{ userData.name }}</h3>
<p>Email: {{ userData.email }}</p>
<p>Phone: {{ userData.phone }}</p>
</div>
</div>
</template>
FAQs
What are the main advantages of the Composition API over the Options API?
The Composition API enables better code organization, improved logic reuse, enhanced TypeScript support, and easier handling of complex components by grouping related logic together rather than spreading it across options like data, methods, and lifecycle hooks.
Can I use the Composition API and Options API together?
Yes, Vue 3 supports using both APIs within the same project or even within the same component, though it's recommended to choose one approach for consistency and maintainability.
Is the Composition API compatible with Vue 2?
The Composition API is built into Vue 3. However, there is a plugin called @vue/composition-api that allows limited use of the Composition API in Vue 2 projects.
How does ref() differ from reactive()?
ref() creates a reactive reference to a primitive value or object, while reactive() makes an entire object reactive. ref() wraps values and exposes them via a .value property, whereas reactive() proxies all properties directly.
What is script setup and why should I use it?
<script setup> is a compiler macro in Vue 3 that simplifies the syntax when using the Composition API, removing the need to explicitly return variables and allowing direct use of imports and reactive variables in the template.
Conclusion
The Composition API is a transformative feature of Vue.js 3 that enhances the way developers build and organize Vue applications. By mastering its core concepts—such as ref(), reactive(), computed(), and watch()—and embracing best practices like using composables and script setup, you can write more maintainable, scalable, and readable Vue components.
This tutorial has walked you through practical examples, tools, and resources to help you confidently adopt the Composition API. Whether you are starting a new project or migrating an existing one, the Composition API equips you with the flexibility and power needed to build modern, efficient Vue applications.