Bird
Raised Fist0
Vueframework~10 mins

Composables for reusable logic in Vue - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - Composables for reusable logic
Create composable function
↓
Define reactive state inside composable
↓
Return state and functions
↓
Import composable in component
↓
Use returned state and functions
↓
Component reacts to composable state changes
↓
Reusable logic shared across components
This flow shows how you create a composable function with reactive state and logic, then use it inside components to share behavior easily.
Execution Sample
Vue
import { ref } from 'vue'

export function useCounter() {
  const count = ref(0)
  function increment() { count.value++ }
  return { count, increment }
}
Defines a composable that provides a reactive count and an increment function.
Execution Table
StepActionState BeforeState AfterOutput/Effect
1Call useCounter()No countcount = 0Composable returns count and increment
2Component uses count.valuecount = 0count = 0Component shows count as 0
3Call increment()count = 0count = 1count.value increments to 1
4Component reacts to count changecount = 1count = 1UI updates to show count as 1
5Call increment() againcount = 1count = 2count.value increments to 2
6Component reacts to count changecount = 2count = 2UI updates to show count as 2
7No more actionscount = 2count = 2Execution stops
💡 No more actions to perform, composable state stable
Variable Tracker
VariableStartAfter Step 1After Step 3After Step 5Final
count.valueundefined0122
Key Moments - 2 Insights
Why does count.value update inside the component when increment() is called?
Because count is a reactive ref returned by the composable, when increment() changes count.value, Vue tracks this and updates the component automatically (see execution_table steps 3 and 4).
Can multiple components use the same composable and keep their own count?
Yes, each call to useCounter() creates a new reactive count ref, so each component has its own independent state (not shown in table but implied by composable pattern).
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table at step 3, what is the value of count after increment() is called?
A0
Bundefined
C1
D2
💡 Hint
Check the 'State After' column at step 3 in execution_table
At which step does the component update its UI to show the new count value?
AStep 2
BStep 4
CStep 5
DStep 1
💡 Hint
Look for 'UI updates' in the Output/Effect column in execution_table
If we call increment() twice, what will count.value be after the second call?
A2
B0
C1
Dundefined
💡 Hint
See variable_tracker for count.value changes after steps 3 and 5
Concept Snapshot
Composable functions in Vue are reusable logic blocks.
They use reactive state like ref() inside.
Return state and functions to components.
Each component calling composable gets independent state.
Components react automatically to reactive changes.
Use composables to share logic cleanly.
Full Transcript
This visual trace shows how Vue composables work. First, you create a composable function that defines reactive state using ref(). It returns this state and any functions that change it. When a component calls this composable, it gets its own reactive state. Calling functions like increment() updates the reactive state. Vue detects these changes and updates the component's UI automatically. Each component using the composable has its own independent state. This pattern helps share logic easily and keeps components clean.

Practice

(1/5)
1. What is the main purpose of a composable in Vue?
easy
A. To reuse reactive logic across multiple components
B. To define global CSS styles
C. To create new Vue directives
D. To register Vue components globally

Solution

  1. Step 1: Understand composables role

    Composables are functions that encapsulate reactive logic to be reused.
  2. Step 2: Identify main purpose

    They help share logic like state or effects across components without duplication.
  3. Final Answer:

    To reuse reactive logic across multiple components -> Option A
  4. Quick Check:

    Composable = reusable logic [OK]
Hint: Composables share logic, not styles or components [OK]
Common Mistakes:
  • Confusing composables with CSS or templates
  • Thinking composables register components
  • Assuming composables create directives
2. Which of the following is the correct way to define a composable in Vue 3?
easy
A. function useCounter() { return reactive({ count: 0 }) }
B. const useCounter = new Vue({ data() { return { count: 0 } } })
C. const useCounter = reactive({ count: 0 })
D. function useCounter() { const count = ref(0); return { count }; }

Solution

  1. Step 1: Check composable function syntax

    A composable is a function that returns reactive state or methods.
  2. Step 2: Validate options

    function useCounter() { const count = ref(0); return { count }; } defines a function returning a ref wrapped count, which is correct. const useCounter = new Vue({ data() { return { count: 0 } } }) wrongly uses Vue instance syntax. const useCounter = reactive({ count: 0 }) returns reactive object directly without function. function useCounter() { return reactive({ count: 0 }) } returns reactive but misses ref usage and best practice.
  3. Final Answer:

    function useCounter() { const count = ref(0); return { count }; } -> Option D
  4. Quick Check:

    Composable = function returning reactive state [OK]
Hint: Composable must be a function returning reactive data [OK]
Common Mistakes:
  • Defining composables as Vue instances
  • Returning reactive objects without a function
  • Not using ref or reactive inside composables
3. Given this composable:
import { ref } from 'vue';
export function useToggle() {
  const isOn = ref(false);
  function toggle() { isOn.value = !isOn.value; }
  return { isOn, toggle };
}
What will be the value of isOn.value after calling toggle() twice starting from initial state?
medium
A. true
B. undefined
C. false
D. null

Solution

  1. Step 1: Analyze initial state and toggle function

    Initially, isOn.value is false. Each toggle flips it to the opposite.
  2. Step 2: Apply two toggles

    First toggle: false -> true. Second toggle: true -> false.
  3. Final Answer:

    false -> Option C
  4. Quick Check:

    Two toggles flip false twice back to false [OK]
Hint: Toggle flips boolean; even toggles return original [OK]
Common Mistakes:
  • Assuming toggle sets true always
  • Forgetting to access .value of ref
  • Confusing initial state with toggled state
4. What is wrong with this composable code?
import { ref } from 'vue';
export function useCount() {
  const count = ref(0);
  function increment() {
    count++;
  }
  return { count, increment };
}
medium
A. The count variable should be declared with reactive()
B. You cannot increment a ref directly with ++ operator
C. ref should be imported from 'vue/reactive' instead
D. The function should be named useCounter, not useCount

Solution

  1. Step 1: Understand ref usage

    Ref values are accessed and mutated via the .value property.
  2. Step 2: Identify error in increment function

    The code uses count++ which tries to increment the ref object itself, not its value. It should be count.value++.
  3. Final Answer:

    You cannot increment a ref directly with ++ operator -> Option B
  4. Quick Check:

    Use count.value++ to update ref [OK]
Hint: Always use .value to read or write ref values [OK]
Common Mistakes:
  • Incrementing ref without .value
  • Confusing reactive and ref imports
  • Thinking function name affects behavior
5. You want to create a composable that tracks window width and updates reactively on resize. Which approach correctly implements this?
hard
A. 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 }; }
B. function useWindowWidth() { const width = ref(window.innerWidth); window.addEventListener('resize', () => { width.value = window.innerWidth; }); return { width }; }
C. function useWindowWidth() { const width = reactive({ value: window.innerWidth }); window.onresize = () => { width.value = window.innerWidth; }; return width; }
D. function useWindowWidth() { const width = ref(0); window.addEventListener('resize', () => { width = window.innerWidth; }); return { width }; }

Solution

  1. Step 1: Understand reactive window width tracking

    We need a ref to hold width and update it on resize events.
  2. Step 2: Check event listener 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 }; } correctly adds listener on mount and removes it on unmount to avoid leaks. function useWindowWidth() { const width = ref(window.innerWidth); window.addEventListener('resize', () => { width.value = window.innerWidth; }); return { width }; } adds listener immediately without cleanup. function useWindowWidth() { const width = reactive({ value: window.innerWidth }); window.onresize = () => { width.value = window.innerWidth; }; return width; } uses reactive incorrectly and overwrites window.onresize. function useWindowWidth() { const width = ref(0); window.addEventListener('resize', () => { width = window.innerWidth; }); return { width }; } tries to assign to ref variable directly, which is invalid.
  3. 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 A
  4. Quick Check:

    Manage listeners with lifecycle hooks [OK]
Hint: Add and remove listeners inside lifecycle hooks [OK]
Common Mistakes:
  • Not removing event listeners causing memory leaks
  • Assigning directly to ref variable instead of .value
  • Overwriting window.onresize instead of adding listener
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard