Skip to content

Composables

Composables are a core and powerful concept in Vue's Composition API. It's a pattern that uses Vue's reactivity API to encapsulate and reuse stateful logic.

What is "Stateful Logic"?

Stateful logic refers to logic that changes over time. For example:

  • Tracking the mouse position on the page.
  • Fetching data from a server and managing its loading and error states.
  • Listening to changes in window size.

In the Options API, we usually use Mixins to reuse this logic, but Mixins have some issues like naming conflicts and unclear sources. Composables provide a clearer, more flexible solution.

Conventions and Rules

A composable is a regular JavaScript function, but it follows some conventions:

  1. Naming: Usually starts with use, for example useMouse(), useFetch(). This is a convention that tells other developers this function uses Vue's reactivity API internally.
  2. Input: Can accept reactive ref or reactive objects as parameters and be able to listen to their changes.
  3. Output: Always returns a regular object containing multiple reactive refs for convenient destructuring in components.

Example: useMouse.js

Let's create a classic composable to track mouse coordinates.

src/composables/useMouse.js

js
import { ref, onMounted, onUnmounted } from 'vue'

// By convention, function name starts with `use`
export function useMouse() {
  // The "state" being encapsulated and managed
  const x = ref(0)
  const y = ref(0)

  // Composables can use lifecycle hooks just like components
  function update(event) {
    x.value = event.pageX
    y.value = event.pageY
  }

  onMounted(() => window.addEventListener('mousemove', update))
  onUnmounted(() => window.removeEventListener('mousemove', update))

  // Expose the managed state through the return value
  return { x, y }
}

What does this function do?

  1. Creates two reactive variables x and y.
  2. Uses onMounted to register a mousemove event listener to update x and y.
  3. Uses onUnmounted to clean up this listener when the component unmounts, preventing memory leaks.
  4. Returns the object containing x and y.

Using in Components

Now, any component can easily reuse this logic.

MouseTracker.vue

vue
<script setup>
// Import the composable
import { useMouse } from '../composables/useMouse.js'

// Call it within the component scope
const { x, y } = useMouse()
</script>

<template>
  Mouse position is at: {{ x }}, {{ y }}
</template>

You can even use it multiple times in the same component, and their states won't interfere with each other.

Advantages

  • Clear Logic: Related logic is encapsulated in the same function rather than scattered across different options.
  • Clear Sources: When using in a component, we clearly know that x and y come from useMouse, unlike Mixins where the source is unclear.
  • Code Reuse: Can easily reuse this stateful logic across any component.
  • TypeScript Friendly: Regular functions and variables make type inference very natural.

Composables are the preferred way to organize and reuse logic in Vue 3 applications, making the codebase cleaner, more maintainable, and extensible.

Content is for learning and research only.