Discover how a simple function can save you hours of repetitive coding in Vue!
Creating a custom composable in Vue - Why You Should Know This
Imagine you have multiple Vue components that need to share the same logic, like fetching data or handling a timer, and you copy-paste the same code into each component.
Copying code everywhere makes your app harder to maintain. If you find a bug or want to improve the logic, you must update every component separately, which is slow and error-prone.
Creating a custom composable lets you write the shared logic once and reuse it easily across components. It keeps your code clean, organized, and easy to update.
import { ref } from 'vue'; export default { setup() { const count = ref(0); function increment() { count.value++; } return { count, increment }; } }
import { ref } from 'vue'; function useCounter() { const count = ref(0); function increment() { count.value++; } return { count, increment }; } export default { setup() { const { count, increment } = useCounter(); return { count, increment }; } }
You can build scalable Vue apps by sharing and reusing logic cleanly without repeating yourself.
Imagine a timer feature used in many parts of your app. With a custom composable, you write the timer logic once and use it everywhere, saving time and avoiding bugs.
Copy-pasting logic across components is hard to maintain.
Custom composables let you share logic cleanly and reuse it easily.
This makes your Vue app more organized and scalable.
Practice
Solution
Step 1: Understand what composables do
Custom composables are functions that encapsulate reactive logic to be reused.Step 2: Identify the purpose in Vue components
They help share logic without repeating code in multiple components.Final Answer:
To reuse reactive logic across multiple components -> Option BQuick Check:
Reusable reactive logic = B [OK]
- Confusing composables with styling or directives
- Thinking composables register components
- Assuming composables handle templates
Solution
Step 1: Check function declaration and return
function useData() { const count = ref(0); return { count }; } declares a function named with 'use' prefix and returns reactive refs.Step 2: Validate reactive usage and return object
function useData() { const count = ref(0); return { count }; } returns an object with the reactive ref, which is correct pattern.Final Answer:
function useData() { const count = ref(0); return { count }; } -> Option AQuick Check:
Composable returns reactive refs in object = D [OK]
- Not returning reactive data
- Returning reactive primitive directly instead of object
- Missing 'use' prefix in function name
increment() twice?import { ref } from 'vue';
export function useCounter() {
const count = ref(0);
function increment() {
count.value++;
console.log(count.value);
}
return { count, increment };
}Solution
Step 1: Understand initial count value
The count starts at 0 as a ref.Step 2: Trace increment calls and console logs
Each increment increases count.value by 1 and logs it immediately.Final Answer:
1 and then 2 -> Option DQuick Check:
Increment twice logs 1 then 2 [OK]
- Confusing ref.value with ref itself
- Assuming count starts at 1
- Thinking console logs before increment
import { ref } from 'vue';
export function useToggle() {
const state = ref(false);
function toggle() {
state = !state;
}
return { state, toggle };
}Solution
Step 1: Check how ref is updated
The code tries to assign 'state = !state', which reassigns the const variable.Step 2: Correct way to update ref value
Should update 'state.value = !state.value' instead of reassigning 'state'.Final Answer:
Cannot reassign a const ref variable directly -> Option CQuick Check:
Update ref.value, not ref variable [OK]
- Reassigning ref variable instead of its value
- Forgetting to use .value to access ref
- Assuming reactive is needed instead of ref
Solution
Step 1: Check reactive state initialization
function useUser() { const user = ref(null); const loading = ref(true); async function fetchUser() { loading.value = true; user.value = await fetch('/api/user').then(r => r.json()); loading.value = false; } fetchUser(); return { user, loading }; } correctly uses ref for user and loading states.Step 2: Verify async fetch and state updates
function useUser() { const user = ref(null); const loading = ref(true); async function fetchUser() { loading.value = true; user.value = await fetch('/api/user').then(r => r.json()); loading.value = false; } fetchUser(); return { user, loading }; } uses async function to set loading true, await fetch, then set loading false.Step 3: Confirm fetch is called inside composable
function useUser() { const user = ref(null); const loading = ref(true); async function fetchUser() { loading.value = true; user.value = await fetch('/api/user').then(r => r.json()); loading.value = false; } fetchUser(); return { user, loading }; } calls fetchUser() immediately to start loading data.Final Answer:
function useUser() { const user = ref(null); const loading = ref(true); async function fetchUser() { loading.value = true; user.value = await fetch('/api/user').then(r => r.json()); loading.value = false; } fetchUser(); return { user, loading }; } -> Option AQuick Check:
Async fetch with reactive refs = A [OK]
- Reassigning reactive or ref variables directly
- Not using async/await properly
- Not updating loading state correctly
Ready to prove it?
Pass the test and this pattern moves unknown
