Bird
Raised Fist0
Vueframework~20 mins

Composables for reusable logic in Vue - Practice Problems & Coding Challenges

Choose your learning style10 modes available
Challenge - 5 Problems
🎖️
Composable Mastery
Get all challenges correct to earn this badge!
Test your skills under time pressure!
❓ component_behavior
intermediate
2:00remaining
What is the output of this Vue composable usage?

Consider this composable and component using it:

import { ref } from 'vue';

export function useCounter() {
  const count = ref(0);
  function increment() {
    count.value++;
  }
  return { count, increment };
}

// In a component setup:
const { count, increment } = useCounter();
increment();
increment();

What is the value of count.value after these calls?

A0
B1
C2
Dundefined
Attempts:
2 left
💡 Hint

Each call to increment() increases count.value by 1.

📝 Syntax
intermediate
2:00remaining
Which option correctly defines a composable that returns a reactive string?

Choose the correct composable function that returns a reactive string message initialized to "Hello".

A
import { reactive } from 'vue';
export function useMessage() {
  const message = reactive('Hello');
  return { message };
}
B
export function useMessage() {
  const message = 'Hello';
  return { message };
}
C
import { reactive } from 'vue';
export function useMessage() {
  const message = reactive({ text: 'Hello' });
  return message.text;
}
D
import { ref } from 'vue';
export function useMessage() {
  const message = ref('Hello');
  return { message };
}
Attempts:
2 left
💡 Hint

Use ref for primitive reactive values like strings.

🔧 Debug
advanced
2:00remaining
Why does this composable cause shared state across components?

Look at this composable:

import { ref } from 'vue';

const count = ref(0);

export function useSharedCounter() {
  function increment() {
    count.value++;
  }
  return { count, increment };
}

When used in multiple components, why do they share the same count value?

ABecause Vue automatically shares all composable state between components.
BBecause <code>count</code> is declared outside the function, so it is shared across all calls.
CBecause the function does not return <code>count</code> properly.
DBecause <code>ref</code> creates a global reactive variable by default.
Attempts:
2 left
💡 Hint

Think about where variables are declared in JavaScript modules.

❓ state_output
advanced
2:00remaining
What is the output of this composable with watchEffect?

Given this composable and usage:

import { ref, watchEffect } from 'vue';

export function useDoubleCounter() {
  const count = ref(1);
  const double = ref(0);

  watchEffect(() => {
    double.value = count.value * 2;
  });

  function increment() {
    count.value++;
  }

  return { count, double, increment };
}

// In component setup:
const { count, double, increment } = useDoubleCounter();
increment();
increment();

What are the final values of count.value and double.value?

A<code>count.value</code> is 3 and <code>double.value</code> is 6
B<code>count.value</code> is 2 and <code>double.value</code> is 4
C<code>count.value</code> is 3 and <code>double.value</code> is 3
D<code>count.value</code> is 1 and <code>double.value</code> is 2
Attempts:
2 left
💡 Hint

watchEffect updates double whenever count changes.

🧠 Conceptual
expert
2:00remaining
Why use composables instead of mixins for reusable logic?

Which reason best explains why Vue composables are preferred over mixins for sharing reusable logic?

AComposables provide better type inference and avoid naming conflicts by using explicit function calls.
BMixins are faster to run but harder to write.
CComposables automatically merge data and methods without conflicts.
DMixins allow better control over lifecycle hooks than composables.
Attempts:
2 left
💡 Hint

Think about clarity and code safety when reusing logic.

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