📖 Scenario: You are building a small Vue 3 app that tracks a counter. You want to organize your code by creating a composable function that holds the counter state and logic. This helps keep your code clean and reusable.
🎯 Goal: Create a composable function using Vue's ref to hold a reactive counter state. Then use this composable inside a component to display and update the counter.
📋 What You'll Learn
Use Vue 3 Composition API with ref for reactive state
Create a composable function named useCounter
Inside the composable, define a reactive variable count initialized to 0
Provide a function increment inside the composable to increase count
Use the composable inside a Vue component to display the current count and a button to increment it
💡 Why This Matters
🌍 Real World
Composables help organize and reuse reactive state and logic in Vue apps, making code cleaner and easier to maintain.
💼 Career
Understanding composables is essential for modern Vue development and is commonly used in professional frontend projects.
Progress0 / 4 steps
1
Create the reactive state in a composable
Create a composable function called useCounter that imports ref from 'vue' and defines a reactive variable count initialized to 0 inside it.
Vue
Hint
Remember to import ref from 'vue' and define count inside the function.
2
Add an increment function to the composable
Inside the useCounter composable, add a function called increment that increases count.value by 1. Return increment along with count.
Vue
Hint
Define increment as a function that adds 1 to count.value.
3
Use the composable inside a Vue component
Create a Vue component using <script setup>. Import useCounter and call it to get count and increment. Use these in the template to show the count and a button that calls increment when clicked.
Vue
Hint
Use <script setup> syntax and bind the button click to increment.
4
Add accessibility and finalize the component
In the template, add an aria-label to the button with the text Increment counter for accessibility. Also, wrap the content in a <section> tag.
Vue
Hint
Use semantic <section> and add aria-label to the button for screen readers.
Practice
(1/5)
1. What is the main purpose of a composable function in Vue 3?
easy
A. To create new Vue components automatically
B. To define global CSS styles for the app
C. To replace the Vue router functionality
D. To reuse reactive state and logic across multiple components
Solution
Step 1: Understand composable function role
Composable functions are designed to share reactive state and logic so multiple components can use them without repeating code.
Step 2: Eliminate unrelated options
Creating new Vue components automatically, defining global CSS styles for the app, and replacing the Vue router functionality are all unrelated to composables.
Final Answer:
To reuse reactive state and logic across multiple components -> Option D
Quick Check:
Composable = reusable reactive logic [OK]
Hint: Composable = reusable reactive logic across components [OK]
Common Mistakes:
Confusing composables with components
Thinking composables handle styling or routing
Assuming composables create UI elements
2. Which of the following is the correct way to create a reactive state inside a composable using Vue 3 Composition API?
easy
A. const count = reactive(0)
B. const count = ref(0)
C. const count = reactive({ value: 0 })
D. const count = ref({ value: 0 })
Solution
Step 1: Recall ref and reactive usage
ref is used to create a reactive primitive like a number, string, or boolean. reactive is for objects.
Step 2: Analyze options
const count = ref(0) correctly uses ref(0) for a reactive number. const count = reactive(0) is invalid because reactive expects an object, not a primitive. const count = reactive({ value: 0 }) wraps a number in an object but is less common for simple primitives. const count = ref({ value: 0 }) uses ref with an object, which works but is less idiomatic than reactive for objects.
Final Answer:
const count = ref(0) -> Option B
Quick Check:
Primitive reactive state uses ref() [OK]
Hint: Use ref() for primitives, reactive() for objects [OK]
Common Mistakes:
Using reactive() with primitive values
Using ref() for complex objects instead of reactive()
Confusing ref({}) and reactive({}) usage
3. Given this composable code, what will be logged when increment() is called twice and then count.value is logged?
B. Cannot assign to reactive object properties directly
C. updateName function is not returned
D. Missing import of ref
Solution
Step 1: Check reactive object usage
The user object is created with reactive and its properties can be updated directly.
Step 2: Verify function and return
The updateName function updates user.name correctly and is returned for use.
Final Answer:
No error, code works correctly -> Option A
Quick Check:
Reactive objects allow direct property assignment [OK]
Hint: reactive objects allow direct property changes [OK]
Common Mistakes:
Thinking reactive properties are read-only
Forgetting to return functions from composable
Confusing ref and reactive usage
5. You want to create a composable that tracks a list of tasks reactively and provides a function to add a new task only if it is not empty. Which of the following implementations correctly achieves this?
hard
A. import { ref } from 'vue';
export function useTasks() {
const tasks = ref([]);
function addTask(task) {
tasks.push(task);
}
return { tasks, addTask };
}
B. import { reactive } from 'vue';
export function useTasks() {
const tasks = reactive([]);
function addTask(task) {
if (task) tasks.value.push(task);
}
return { tasks, addTask };
}
C. import { ref } from 'vue';
export function useTasks() {
const tasks = ref([]);
function addTask(task) {
if (task) tasks.value.push(task);
}
return { tasks, addTask };
}
D. import { reactive } from 'vue';
export function useTasks() {
const tasks = reactive([]);
function addTask(task) {
if (task.length > 0) tasks.value.push(task);
}
return { tasks, addTask };
}
Solution
Step 1: Choose correct reactive type for array
Arrays as reactive state are best handled with ref([]) so we access the array via tasks.value.
Step 2: Validate addTask function logic
import { ref } from 'vue';
export function useTasks() {
const tasks = ref([]);
function addTask(task) {
if (task) tasks.value.push(task);
}
return { tasks, addTask };
} checks if task is truthy (not empty) before pushing to tasks.value, which is correct. import { reactive } from 'vue';
export function useTasks() {
const tasks = reactive([]);
function addTask(task) {
if (task) tasks.value.push(task);
}
return { tasks, addTask };
} uses reactive([]) but incorrectly accesses tasks.value.push(task) since reactive does not have a value property. import { ref } from 'vue';
export function useTasks() {
const tasks = ref([]);
function addTask(task) {
tasks.push(task);
}
return { tasks, addTask };
} pushes without checking if task is empty. import { reactive } from 'vue';
export function useTasks() {
const tasks = reactive([]);
function addTask(task) {
if (task.length > 0) tasks.value.push(task);
}
return { tasks, addTask };
} incorrectly tries to access tasks.value when tasks is reactive, which does not have a value property.
Final Answer:
use ref([]) with if (task) tasks.value.push(task) -> Option C
Quick Check:
Use ref([]) for arrays and check input before push [OK]
Hint: Use ref([]) for reactive arrays and check input before push [OK]
Common Mistakes:
Using reactive([]) for arrays instead of ref([])
Forgetting to check if task is empty
Accessing .value on reactive arrays
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.