0Pricing
Frontend Academy · Lesson

Composables: Reusable Composition Functions

Extract reactive logic into composable functions prefixed with use, share them across components, and understand how they differ from mixins.

Composables: Reusable Composition Functions is a free Frontend Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Frontend Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

What Are Composables?

A composable is a function that uses Composition API hooks to encapsulate and reuse stateful logic. They're the Composition API equivalent of mixins — but without namespace collisions or hidden dependencies.

A Basic Composable

Extract reactive logic into a function starting with use. It can use ref, computed, watch, and lifecycle hooks — just like setup().

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

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

// Usage in any component:
const { count, increment } = useCounter(10);

Composable with Lifecycle Hooks

Composables can register lifecycle hooks. The hooks fire relative to the component that calls the composable.

// useOnlineStatus.ts
import { ref, onMounted, onUnmounted } from 'vue';

export function useOnlineStatus() {
  const isOnline = ref(navigator.onLine);

  const update = () => (isOnline.value = navigator.onLine);

  onMounted(() => {
    window.addEventListener('online', update);
    window.addEventListener('offline', update);
  });
  onUnmounted(() => {
    window.removeEventListener('online', update);
    window.removeEventListener('offline', update);
  });

  return { isOnline };
}

Composable with Async (useFetch)

Composables work great for async data fetching — encapsulate the loading/error/data pattern.

// useFetch.ts
export function useFetch<T>(url: MaybeRef<string>) {
  const data = ref<T | null>(null);
  const loading = ref(true);
  const error = ref<string | null>(null);

  watchEffect(async (onCleanup) => {
    const controller = new AbortController();
    onCleanup(() => controller.abort());
    loading.value = true;
    error.value = null;
    try {
      const res = await fetch(unref(url), { signal: controller.signal });
      data.value = await res.json();
    } catch (e: any) {
      if (e.name !== 'AbortError') error.value = e.message;
    } finally { loading.value = false; }
  });

  return { data, loading, error };
}

Accepting Refs as Parameters

Composables can accept either plain values or refs as arguments using MaybeRef<T> (= T | Ref<T>) and unref() to access the value.

import type { MaybeRef } from 'vue';
import { unref } from 'vue';

function useDouble(num: MaybeRef<number>) {
  return computed(() => unref(num) * 2);
}

Composables vs Mixins

Mixins inject properties into the component without clear origin. Composables are explicit — you see exactly what a composable provides from its return value. Multiple composables can be used without naming conflicts.

Sharing State Between Components

If a composable calls ref() inside itself, each component that calls the composable gets its own state. To share state across components, call ref() at module scope (outside the composable function).

// Shared state (module-level):
const sharedCount = ref(0);

export function useSharedCounter() {
  // All callers share the same sharedCount
  return { count: sharedCount, increment: () => sharedCount.value++ };
}

Composable Libraries

VueUse (vueuse.org) provides 200+ ready-to-use composables: useLocalStorage, useFetch, useDark, useIntersectionObserver, and many more. Always check VueUse before writing from scratch.

Testing Composables

Test composables by calling them inside a small test component or using @vue/test-utils mountedApp pattern. Vitest integrates well with Vue's reactivity system.

Composable Naming Conventions

Always prefix with use (useAuth, useFetch, useMediaQuery). Keep them focused on a single concern. Avoid composables that do too many unrelated things.

Composable Organisation

Create a composables/ folder. One file per composable. Index file re-exports all composables. This mirrors how custom hooks are organised in React projects.

Quick Check

What is the key advantage of composables over Vue mixins?

Recap: Vue Composables

A composable is a use-prefixed function that calls Composition API hooks. Each caller gets independent state unless you use module-level refs. Accept refs or values with MaybeRef + unref. Register lifecycle hooks inside composables. Check VueUse before writing your own. Explicit return values prevent mixin-style namespace pollution.

Frequently asked questions

Is the “Composables: Reusable Composition Functions” lesson free?

Yes — the full text of “Composables: Reusable Composition Functions” is free to read here on the web, and the Frontend Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Frontend Academy course, upgrade to CoddyKit PRO.

What will I learn in “Composables: Reusable Composition Functions”?

Extract reactive logic into composable functions prefixed with use, share them across components, and understand how they differ from mixins. You practise Frontend Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Frontend Academy?

No prior experience is required. Frontend Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Composables: Reusable Composition Functions” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Frontend Academy lesson?

Yes. Every Frontend Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. ref() and reactive()
  2. computed() and watch()
  3. The setup() Function and script setup
  4. Composables: Reusable Composition Functions
← Back to Frontend Academy