Discover how composables can save you hours of debugging and rewriting code!
Why composables matter in Vue - The Real Reasons
Imagine building a Vue app where you copy and paste the same logic in multiple components to handle things like fetching data or managing user input.
Copying code everywhere makes your app hard to maintain, bugs spread easily, and updating one place means hunting down all copies manually.
Composables let you write reusable logic once and share it across components cleanly, keeping your code DRY and easy to update.
setup() { const count = ref(0); function increment() { count.value++ } return { count, increment } }function useCounter() { const count = ref(0); function increment() { count.value++ } return { count, increment } }Composables unlock clean, reusable, and testable logic that scales effortlessly as your app grows.
Imagine a login form and a profile page both needing to track user authentication state; composables let you share that logic without repeating code.
Manual code duplication leads to bugs and hard maintenance.
Composables package logic for easy reuse across components.
This approach keeps your Vue app clean, scalable, and easier to update.
Practice
Solution
Step 1: Understand composables' purpose
Composables are functions that let you reuse logic in Vue components.Step 2: Identify the correct benefit
They help keep components clean by sharing logic, not styling or routing.Final Answer:
They help reuse logic across multiple components easily. -> Option DQuick Check:
Reusing logic = composables importance [OK]
- Thinking composables handle styling
- Confusing composables with routing
- Believing composables compile templates
Solution
Step 1: Recall composable syntax
Composables are functions that return reactive state or methods.Step 2: Check each option
function useCounter() { const count = ref(0); return { count }; } defines a function returning a reactive ref, which is correct. Others misuse class, VueComponent, or this context.Final Answer:
function useCounter() { const count = ref(0); return { count }; } -> Option AQuick Check:
Composable = function returning reactive state [OK]
- Using class syntax for composables
- Trying to use 'this' inside arrow functions
- Confusing composables with components
function useToggle() {
const on = ref(false);
function toggle() { on.value = !on.value; }
return { on, toggle };
}What will be the value of
on.value after calling toggle() twice starting from initial state?Solution
Step 1: Understand initial state
The refonstarts asfalse.Step 2: Apply toggle twice
First toggle flipsfalsetotrue. Second toggle flipstrueback tofalse.Final Answer:
false -> Option CQuick Check:
Toggle twice returns to initial false [OK]
- Assuming toggle only flips once
- Confusing ref.value with ref itself
- Expecting undefined or null values
function useData() {
const data = ref(null);
fetch('api/data').then(response => {
data.value = response.json();
});
return { data };
}Solution
Step 1: Analyze fetch usage
fetch returns a promise; response.json() also returns a promise.Step 2: Identify mistake in assigning data.value
Assigning data.value = response.json() sets it to a promise, not resolved data.Final Answer:
fetch returns a promise, so data.value is set to a promise, not actual data. -> Option AQuick Check:
response.json() returns promise, must await [OK]
- Not awaiting response.json()
- Thinking ref can't start as null
- Believing fetch is disallowed in composables
Solution
Step 1: Understand reactive state and lifecycle
We need reactive width and proper event listener cleanup to avoid leaks.Step 2: Evaluate options for lifecycle management
function useWindowWidth() { const width = ref(window.innerWidth); onMounted(() => { window.addEventListener('resize', () => { width.value = window.innerWidth; }); }); onUnmounted(() => { window.removeEventListener('resize', () => { width.value = window.innerWidth; }); }); return { width }; } uses onMounted and onUnmounted to add and remove listeners correctly, ensuring cleanup.Final Answer:
function useWindowWidth() { const width = ref(window.innerWidth); onMounted(() => { window.addEventListener('resize', () => { width.value = window.innerWidth; }); }); onUnmounted(() => { window.removeEventListener('resize', () => { width.value = window.innerWidth; }); }); return { width }; } -> Option BQuick Check:
Use lifecycle hooks to add/remove listeners [OK]
- Not removing event listeners causing memory leaks
- Using non-reactive variables for width
- Using setInterval instead of event listeners
Ready to prove it?
Pass the test and this pattern moves unknown
