Skip to main content
Vue.js Essentials·Lesson 3 of 5

The Composition API

The Composition API is Vue 3's answer to a real problem: in large components, related logic gets scattered across different option sections (data, methods, computed, watch). The Composition API lets you organise logic by feature, not by option type.

Computed Properties

Computed properties are derived values that automatically update when their dependencies change:

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

const firstName = ref('Sabaoon')
const lastName = ref('Dev')

const fullName = computed(() => `${firstName.value} ${lastName.value}`)
// fullName updates automatically when firstName or lastName changes
</script>

Computed properties are cached — they only recalculate when their reactive dependencies change. Use them instead of methods when you need a derived value in the template.

Watchers

Watchers run side effects when reactive values change:

<script setup>
import { ref, watch, watchEffect } from 'vue'

const searchQuery = ref('')

// watch: explicit about what to watch
watch(searchQuery, (newValue, oldValue) => {
  console.log(`Search changed from "${oldValue}" to "${newValue}"`)
  fetchResults(newValue)
})

// watchEffect: automatically tracks dependencies
watchEffect(() => {
  // This runs immediately and re-runs when searchQuery changes
  document.title = `Search: ${searchQuery.value}`
})
</script>

Use watch when you need the old value or want to control when the watcher first runs. Use watchEffect when you want it to run immediately and track dependencies automatically.

Lifecycle Hooks

Vue provides lifecycle hooks to run code at specific points in a component's life:

<script setup>
import { onMounted, onUnmounted, onUpdated } from 'vue'

onMounted(() => {
  // Component is in the DOM — safe to access DOM elements
  console.log('Component mounted')
})

onUpdated(() => {
  // Component re-rendered due to state change
})

onUnmounted(() => {
  // Component is being removed — clean up event listeners, timers, etc.
})
</script>

Composables — Reusable Logic

Composables are functions that encapsulate and reuse stateful logic:

// composables/useCounter.ts
import { ref, computed } from 'vue'

export function useCounter(initialValue = 0) {
  const count = ref(initialValue)
  const doubled = computed(() => count.value * 2)
  
  function increment() { count.value++ }
  function decrement() { count.value-- }
  function reset() { count.value = initialValue }
  
  return { count, doubled, increment, decrement, reset }
}
<!-- Usage in any component -->
<script setup>
import { useCounter } from '@/composables/useCounter'

const { count, doubled, increment } = useCounter(10)
</script>

Composables are the Composition API's answer to React's hooks — reusable, testable logic that isn't tied to a specific component.

A Real-World Composable: useLocalStorage

import { ref, watch } from 'vue'

export function useLocalStorage<T>(key: string, defaultValue: T) {
  const stored = localStorage.getItem(key)
  const value = ref<T>(stored ? JSON.parse(stored) : defaultValue)
  
  watch(value, (newValue) => {
    localStorage.setItem(key, JSON.stringify(newValue))
  }, { deep: true })
  
  return value
}

This composable makes any reactive value automatically persist to localStorage — reusable across every component that needs it.