📖 Scenario: You are building a Vue 3 app with multiple components that need to share the same reactive counter logic.Instead of duplicating code, you will create a composable function to hold the counter state and increment logic.
🎯 Goal: Create a composable function useCounter that provides a reactive count and an increment function. Then use this composable in two separate components to share the counter state.
📋 What You'll Learn
Create a composable function named useCounter that returns a reactive count and an increment function.
Use Vue's ref to make count reactive.
Create two components named CounterOne and CounterTwo that both use useCounter.
Display the current count and a button to call increment in each component.
💡 Why This Matters
🌍 Real World
Composables let you write reusable logic once and use it in many components, saving time and reducing bugs.
💼 Career
Understanding composables is essential for Vue developers to build clean, maintainable, and scalable applications.
Progress0 / 4 steps
1
Create the composable function useCounter
Create a composable function named useCounter that uses Vue's ref to create a reactive variable called count initialized to 0. Also create a function named increment that increases count.value by 1. Return both count and increment from useCounter. Use import { ref } from 'vue' at the top.
Vue
Hint
Use ref(0) to create a reactive count. Define increment to add 1 to count.value. Return both in an object.
2
Create the CounterOne component using useCounter
Create a Vue component named CounterOne using <script setup>. Import the useCounter composable. Call useCounter() and destructure count and increment. In the template, display the text Counter One: {{ count }} and a button with text Increment that calls increment on click.
Vue
Hint
Use <script setup> syntax. Import useCounter and call it to get count and increment. Use a button with @click to call increment.
3
Create the CounterTwo component using useCounter
Create a Vue component named CounterTwo using <script setup>. Import the useCounter composable. Call useCounter() and destructure count and increment. In the template, display the text Counter Two: {{ count }} and a button with text Increment that calls increment on click.
Vue
Hint
Repeat the same pattern as CounterOne but change the displayed text to Counter Two.
4
Use both components in a parent component
Create a parent Vue component named App using <script setup>. Import CounterOne and CounterTwo components. Register them locally by importing. In the template, include both <CounterOne /> and <CounterTwo /> tags to display both counters on the page.
Vue
Hint
Import both components and include them in the template using their tags.
Practice
(1/5)
1. What is the main purpose of a composable in Vue 3? function useCounter() { const count = ref(0); return { count }; }
easy
A. To register global Vue directives
B. To define a new component template
C. To style components with CSS
D. To share reusable reactive logic across multiple components
Solution
Step 1: Understand what a composable function does
A composable is a function that returns reactive state or methods to be reused.
Step 2: Identify the purpose of the example composable
The example returns a reactive count variable to share logic across components.
Final Answer:
To share reusable reactive logic across multiple components -> Option D
Quick Check:
Composable = reusable logic [OK]
Hint: Composable functions return reactive state for reuse [OK]
Common Mistakes:
Thinking composables define templates
Confusing composables with CSS styling
Assuming composables register directives
2. Which is the correct way to import and use a composable named useTimer inside a Vue component's setup() function?
easy
A. import { useTimer } from './composables'; const { time } = useTimer();
B. import useTimer from './composables'; const time = useTimer;
C. const useTimer = require('./composables'); const { time } = useTimer();
D. import useTimer from './composables'; setup() { return useTimer; }
Solution
Step 1: Import the composable correctly
Use ES module import syntax with curly braces if composable is a named export.
Step 2: Call the composable function inside setup()
Call useTimer() to get reactive state, then destructure needed properties.
Final Answer:
import { useTimer } from './composables'; const { time } = useTimer(); -> Option A
Quick Check:
Import named + call function = correct usage [OK]
Hint: Import named composable and call it inside setup() [OK]
Common Mistakes:
Using require() instead of import
Not calling the composable function
Importing default when composable is named export
3. Given this composable and component code, what will be logged?
Count starts at 0 and increments by 1 each time increment() is called.
Step 2: Trace component setup execution
Increment is called twice, so count.value becomes 2, then logged.
Final Answer:
2 -> Option A
Quick Check:
Two increments = count 2 [OK]
Hint: Count increments twice, so value is 2 [OK]
Common Mistakes:
Forgetting to call increment()
Confusing ref with plain variable
Expecting count to be 0 without increments
4. Identify the error in this composable usage:
import { ref } from 'vue';
export function useData() {
const data = ref(null);
fetch('/api').then(res => res.json()).then(json => data = json);
return { data };
}
medium
A. Using ref instead of reactive
B. Missing await keyword before fetch
C. Reassigning the ref variable instead of its value
D. Not returning the data variable
Solution
Step 1: Check how ref is updated
Ref variables must update their .value, not be reassigned.
Step 2: Identify the mistake in the fetch callback
The code assigns data = json instead of data.value = json.
Final Answer:
Reassigning the ref variable instead of its value -> Option C
Quick Check:
Update ref.value, not ref itself [OK]
Hint: Update ref.value, not the ref variable [OK]
Common Mistakes:
Assigning directly to ref variable
Forgetting to handle async properly
Confusing reactive with ref usage
5. You want to share a composable that tracks a user's online status across multiple components. Which approach ensures each component has its own independent reactive state?
hard
A. Export a single reactive object and import it directly in all components
B. Export a function that returns new refs each call, then import and call it in each component
C. Define reactive state inside a global variable outside the composable
D. Use a Vuex store instead of composables for reactive state
Solution
Step 1: Understand independent reactive state per component
Each component needs its own fresh reactive refs to avoid shared state.
Step 2: Identify correct composable pattern
Exporting a function that returns new refs each call creates isolated state per component.
Final Answer:
Export a function that returns new refs each call, then import and call it in each component -> Option B
Quick Check:
Function returns fresh state per call [OK]
Hint: Return new refs inside function for isolated state [OK]
Common Mistakes:
Sharing a single reactive object causing shared state
Using global variables outside composables
Confusing Vuex with composables for local state
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.