Vue Academy · Lesson

useCounter: A Simple Composable

count ref, increment/decrement functions, reset, exposing only what's needed.

Lesson 2 of 413 steps

useCounter: A Simple Composable is a free Vue Academy lesson on CoddyKit. This is lesson 2 of 4. Any 3 lessons of this learning path are free to read in full — after that, CoddyKit PRO unlocks every lesson, plus hands-on practice with a built-in code editor and a 24/7 AI tutor. It is part of the Vue Academy learning path, and your progress syncs across the web and the CoddyKit app. The Vue Academy course includes 4 lessons in total.

Building useCounter

We will write a small but complete composable: useCounter. It manages a number and exposes methods to change it - a perfect first composable.

Accepting an Initial Value

Give the function an initial parameter with a default so callers can start the counter anywhere.

function useCounter(initial = 0) {
  // ...
}

The Internal count Ref

Inside, create a ref for the count, seeded with the initial value. This is the reactive state the composable owns.

import { ref } from "vue";
function useCounter(initial = 0) {
  const count = ref(initial);
}

The increment Function

Define a function that mutates the ref. Because count is reactive, every consumer updates automatically.

function increment() {
  count.value++;
}

decrement and reset

Add the complementary actions. reset uses the original initial captured in the closure.

function decrement() {
  count.value--;
}
function reset() {
  count.value = initial;
}

Returning the API

Return an object with the reactive state and all methods. This is the composable public interface.

return { count, increment, decrement, reset };

The Full Composable

Putting it together, the whole thing is compact and reusable across any component.

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 };
}

Using It in a Component

Call it in <script setup> and destructure. The template can use count directly (auto-unwrapped) and bind the methods.

const { count, increment, decrement, reset } = useCounter(10);

In the Template

Wire the methods to buttons. Each click mutates the shared ref and the view updates.

<button @click="decrement">-</button>
<span>{{ count }}</span>
<button @click="increment">+</button>

Independent Instances

Each call to useCounter creates its own count ref. Two components calling it get separate, isolated counters.

const a = useCounter();   // own count
const b = useCounter(100); // own count

Adding Computed Extras

You can enrich the composable with derived state, like an isZero computed, returned alongside the rest.

import { computed } from "vue";
const isZero = computed(() => count.value === 0);
// add to return: { count, isZero, increment, ... }

Quick Check

Why does each call to useCounter get its own state?

Recap

You built useCounter(initial): an internal count ref, increment/decrement/reset functions, and a returned object exposing reactive state plus methods. Each call yields an independent instance.

Free to start

Learn HTML with an AI tutor — free

Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.

Courses
42
Lessons
156

Frequently Asked Questions

Is the “useCounter: A Simple Composable” lesson free?

Yes — any 3 lessons of the Vue Academy learning path, including “useCounter: A Simple Composable”, are free to read in full here on the web. After that, CoddyKit PRO unlocks every lesson, plus interactive practice with a built-in code editor and a 24/7 AI tutor. The Vue Academy course includes 4 lessons in total.

What will I learn in “useCounter: A Simple Composable”?

count ref, increment/decrement functions, reset, exposing only what's needed. You practise Vue 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 Vue Academy?

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

How long does the “useCounter: A Simple Composable” 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 Vue Academy lesson?

Yes. Every Vue 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. What Makes a Good Composable
  2. useCounter: A Simple Composable
  3. useFetch: Async Data Composable
  4. VueUse: The Composable Library
← Back to Vue Academy