Bird
Raised Fist0
Vueframework~5 mins

Composable with reactive state in Vue

Choose your learning style10 modes available
Introduction

A composable with reactive state helps you organize and reuse reactive data and logic in Vue components easily.

You want to share reactive data and functions between multiple components.
You want to keep your component code clean by moving logic out.
You want to create reusable features like counters or form handlers.
You want to separate concerns in your app for easier maintenance.
Syntax
Vue
import { ref } from 'vue';

export function useExample(initialValue) {
  const state = ref(initialValue);

  function updateState(newValue) {
    state.value = newValue;
  }

  return { state, updateState };
}

Use ref to create reactive state that updates the UI automatically.

Return the reactive state and functions so components can use them.

Examples
A simple counter composable with reactive count and increment function.
Vue
import { ref } from 'vue';

export function useCounter() {
  const count = ref(0);
  function increment() {
    count.value++;
  }
  return { count, increment };
}
Using reactive for an object state with multiple properties.
Vue
import { reactive } from 'vue';

export function useUser() {
  const user = reactive({ name: '', age: 0 });
  function updateName(newName) {
    user.name = newName;
  }
  return { user, updateName };
}
Sample Program

This Vue component uses a composable useToggle to manage a reactive boolean state. Clicking the button toggles the state between ON and OFF.

Vue
<script setup>
import { ref } from 'vue';

function useToggle() {
  const isOn = ref(false);
  function toggle() {
    isOn.value = !isOn.value;
  }
  return { isOn, toggle };
}

const { isOn, toggle } = useToggle();
</script>

<template>
  <button @click="toggle" :aria-pressed="isOn">
    {{ isOn ? 'ON' : 'OFF' }}
  </button>
</template>
OutputSuccess
Important Notes

Always return reactive state and functions from composables to keep logic reusable.

Use ref for simple values and reactive for objects.

Composable functions should start with use to follow Vue conventions.

Summary

Composable functions help reuse reactive state and logic across components.

Use ref or reactive to create reactive state inside composables.

Return state and functions from composables so components can use them easily.

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

  1. 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.
  2. 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.
  3. Final Answer:

    To reuse reactive state and logic across multiple components -> Option D
  4. 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

  1. 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.
  2. 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.
  3. Final Answer:

    const count = ref(0) -> Option B
  4. 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?
import { ref } from 'vue';
export function useCounter() {
  const count = ref(0);
  function increment() {
    count.value++;
  }
  return { count, increment };
}

const { count, increment } = useCounter();
increment();
increment();
console.log(count.value);
medium
A. 2
B. 0
C. 1
D. undefined

Solution

  1. Step 1: Understand initial state and increments

    The count starts at 0. Each call to increment() increases count.value by 1.
  2. Step 2: Calculate final value after two increments

    After two calls, count.value = 0 + 1 + 1 = 2.
  3. Final Answer:

    2 -> Option A
  4. Quick Check:

    Two increments add 2 to count.value [OK]
Hint: Increment ref.value to update reactive count [OK]
Common Mistakes:
  • Forgetting to access .value on ref
  • Assuming count is a plain number, not ref
  • Confusing initial value with updated value
4. Identify the error in this composable code snippet:
import { reactive } from 'vue';
export function useUser() {
  const user = reactive({ name: 'Alice', age: 30 });
  function updateName(newName) {
    user.name = newName;
  }
  return { user, updateName };
}

const { user, updateName } = useUser();
updateName('Bob');
console.log(user.name);
medium
A. No error, code works correctly
B. Cannot assign to reactive object properties directly
C. updateName function is not returned
D. Missing import of ref

Solution

  1. Step 1: Check reactive object usage

    The user object is created with reactive and its properties can be updated directly.
  2. Step 2: Verify function and return

    The updateName function updates user.name correctly and is returned for use.
  3. Final Answer:

    No error, code works correctly -> Option A
  4. 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

  1. 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.
  2. 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.
  3. Final Answer:

    use ref([]) with if (task) tasks.value.push(task) -> Option C
  4. 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 unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard