Vue.js Composition API

Vue.js is a popular JavaScript framework used for building interactive user interfaces and single-page applications. With the release of Vue 3, the Composition API was introduced as a powerful new way to organize and reuse code within Vue components. This chapter will explore the Composition API in detail, starting from the basics and moving towards advanced concepts. By the end of this chapter, you will have a thorough understanding of how to use the Composition API effectively in your Vue.js projects.

What is the Composition API?

The Composition API is a set of additive, function-based APIs that allow you to compose component logic in a more flexible and readable way compared to the Options API. It is inspired by React’s Hooks and enables better code organization, reuse, and type inference

Why Use the Composition API?

The Composition API offers several advantages over the traditional Options API:

Improved Code Organization

It allows you to group related code by feature rather than by lifecycle hook, making your components more readable and maintainable.

Enhanced Reusability

Logic can be easily extracted into reusable functions, known as composables, which can be shared across different components.

Better Type Inference

With TypeScript, the Composition API provides better type inference and autocompletion, leading to fewer runtime errors.

Setup and Installation

Before using the Composition API, ensure you have Vue 3 installed. If you are starting a new project, you can create a Vue 3 project using Vue CLI.

Installation

First, install Vue CLI if you haven’t already:

				
					npm install -g @vue/cli

				
			

Then, create a new Vue 3 project:

				
					vue create my-vue3-project
cd my-vue3-project

				
			

Select the default Vue 3 preset or manually choose Vue 3 features.

Basic Concepts

setup Function

The setup function is the entry point for using the Composition API in a component. It is called before any lifecycle hooks and serves as a place to declare reactive state, computed properties, and methods.

Example

				
					<template>
  <div>{{ message }}</div>
</template> <script type="litespeed/javascript">import{ref}from 'vue';export default{setup(){const message=ref('Hello, Vue 3!');return{message,}},}</script> 
				
			

Explanation

  • The ref function is used to create a reactive reference.
  • The setup function returns an object that exposes the reactive properties to the template.

reactive and ref

The ref and reactive functions are used to create reactive state.

Example with ref

				
					<template>
  <div>{{ count }}</div>
  <button @click="increment">Increment</button>
</template> <script type="litespeed/javascript">import{ref}from 'vue';export default{setup(){const count=ref(0);const increment=()=>{count.value++};return{count,increment,}},}</script> 
				
			

Explanation

  • ref creates a reactive reference. To access or modify its value, use count.value.

Example with reactive

				
					<template>
  <div>{{ state.count }}</div>
  <button @click="increment">Increment</button>
</template> <script type="litespeed/javascript">import{reactive}from 'vue';export default{setup(){const state=reactive({count:0,});const increment=()=>{state.count++};return{state,increment,}},}</script> 
				
			

Explanation

  • reactive creates a reactive object. Access properties directly from the object, e.g., state.count.

Computed Properties

Computed properties are derived state that depends on other reactive state. Use the computed function to create them.

Example

				
					<template>
  <div>{{ doubleCount }}</div>
</template> <script type="litespeed/javascript">import{ref,computed}from 'vue';export default{setup(){const count=ref(2);const doubleCount=computed(()=>count.value*2);return{doubleCount,}},}</script> 
				
			

Explanation

  • The computed function takes a getter function and returns a reactive computed property.

Advanced Concepts

Watchers

Watchers allow you to perform side effects in response to reactive state changes. Use the watch function to create watchers.

Example

				
					<template>
  <div>{{ count }}</div>
  <button @click="increment">Increment</button>
</template> <script type="litespeed/javascript">import{ref,watch}from 'vue';export default{setup(){const count=ref(0);const increment=()=>{count.value++};watch(count,(newValue,oldValue)=>{console.log(`Count changed from ${oldValue} to ${newValue}`)});return{count,increment,}},}</script> 
				
			

Explanation

  • watch takes two arguments: the reactive source to watch and a callback function that runs when the source changes.

Lifecycle Hooks

The Composition API provides equivalents for all the Options API lifecycle hooks. These hooks can be used inside the setup function.

Example

				
					<template>
  <div>{{ message }}</div>
</template> <script type="litespeed/javascript">import{ref,onMounted,onUnmounted}from 'vue';export default{setup(){const message=ref('Hello, Vue 3!');onMounted(()=>{console.log('Component mounted')});onUnmounted(()=>{console.log('Component unmounted')});return{message,}},}</script> 
				
			

Explanation

  • onMounted and onUnmounted are used to register code that runs when the component is mounted and unmounted, respectively.

Provide and Inject

The provide and inject functions allow you to pass data from a parent component to its descendants, similar to dependency injection.

Example

				
					// ParentComponent.vue
<template>
  <ChildComponent />
</template> <script type="litespeed/javascript">import{provide,ref}from 'vue';import ChildComponent from './ChildComponent.vue';export default{components:{ChildComponent,},setup(){const message=ref('Hello from parent');provide('message',message)},}</script> // ChildComponent.vue
<template>
  <div>{{ message }}</div>
</template> <script type="litespeed/javascript">import{inject}from 'vue';export default{setup(){const message=inject('message');return{message,}},}</script> 
				
			

Explanation

  • provide makes a value available to all descendants.
  • inject is used to access the provided value in a descendant component.

Custom Composables

Custom composables are reusable functions that encapsulate state and logic. They follow a similar pattern to Vue components but can be used across multiple components.

Example

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

export function useCounter() {
  const count = ref(0);
  const increment = () => {
    count.value++;
  };
  return {
    count,
    increment,
  };
}

// CounterComponent.vue
<template>
  <div>{{ count }}</div>
  <button @click="increment">Increment</button>
</template> <script type="litespeed/javascript">import{useCounter}from './useCounter';export default{setup(){const{count,increment}=useCounter();return{count,increment,}},}</script> 
				
			

Explanation

  • useCounter is a custom composable that provides a counter state and increment function.
  • It can be reused in any component.

Real-world Examples

Form Handling

Let’s create a form component that uses the Composition API to manage form state and validation.

FormComponent.vue

				
					<template>
  <form @submit.prevent="submitForm">
    <div>
      <label for="name">Name:</label>
      <input id="name" v-model="name" />
      <span v-if="nameError">{{ nameError }}</span>
    </div>
    <div>
      <label for="email">Email:</label>
      <input id="email" v-model="email" />
      <span v-if="emailError">{{ emailError }}</span>
    </div>
    <button type="submit">Submit</button>
  </form>
</template> <script type="litespeed/javascript">import{ref,computed}from 'vue';export default{setup(){const name=ref('');const email=ref('');const nameError=computed(()=>{return name.value.length<3?'Name must be at least 3 characters long':''});const emailError=computed(()=>{return!/\S+@\S+\.\S+/.test(email.value)?'Email must be valid':''});const submitForm=()=>{if(!nameError.value&&!emailError.value){alert(`Submitted: ${name.value}, ${email.value}`)}};return{name,email,nameError,emailError,submitForm,}},}</script> 
				
			

Explanation

  • ref is used to create reactive form fields.
  • computed properties are used for validation.
  • The form is submitted only if there are no validation errors.

Fetching Data from an API

Let’s create a component that fetches data from an API using the Composition API.

DataFetchComponent.vue

				
					<template>
  <div>
    <div v-if="loading">Loading...</div>
    <div v-if="error">{{ error }}</div>
    <div v-if="data">{{ data }}</div>
  </div>
</template> <script type="litespeed/javascript">import{ref,onMounted}from 'vue';export default{setup(){const data=ref(null);const loading=ref(!1);const error=ref(null);const fetchData=async()=>{loading.value=!0;try{const response=await fetch('https://api.example.com/data');if(!response.ok)throw new Error('Failed to fetch data');const result=await response.json();data.value=result}catch(err){error.value=err.message}finally{loading.value=!1}};onMounted(fetchData);return{data,loading,error,}},}</script> 
				
			

Explanation

  • ref is used to create reactive state for data, loading, and error.
  • onMounted is used to fetch data when the component mounts.
  • The template conditionally renders content based on the state.

The Composition API in Vue.js provides a flexible and powerful way to organize and reuse component logic. By mastering the basic and advanced concepts of the Composition API, you can create more maintainable and scalable Vue applications. Happy coding !❤️

Table of Contents

Contact here

Copyright © 2025 Diginode

Made with ❤️ in India