Bird
Raised Fist0
Vueframework~8 mins

Composable with reactive state in Vue - Performance & Optimization

Choose your learning style10 modes available
Performance: Composable with reactive state
MEDIUM IMPACT
This affects how efficiently the UI updates when reactive state changes, impacting interaction responsiveness and rendering speed.
Sharing reactive state across components using composables
Vue
import { ref } from 'vue';

export function useCounter() {
  const count = ref(0);
  return { count };
}
Each component gets its own reactive state, so updates only affect that component, reducing unnecessary re-renders.
📈 Performance GainReduces re-renders to only affected components, improving interaction responsiveness.
Sharing reactive state across components using composables
Vue
import { reactive } from 'vue';

const state = reactive({ count: 0 });

export function useCounter() {
  return { state };
}
All components using this composable share the same reactive object, causing all to re-render on any change, even if unrelated.
📉 Performance CostTriggers re-renders in all dependent components on any state change, increasing INP latency.
Performance Comparison
PatternDOM OperationsReflowsPaint CostVerdict
Shared reactive state in composableMany components update DOM nodesMultiple reflows triggeredHigh paint cost due to wide updates[X] Bad
Instance-specific reactive state in composableOnly affected component updates DOMSingle reflow per updateLower paint cost focused on small area[OK] Good
Rendering Pipeline
Reactive state changes trigger Vue's reactivity system, which schedules component updates. These updates cause the browser to recalculate styles, layout, and paint only for affected components.
→JavaScript Execution
→Style Calculation
→Layout
→Paint
→Composite
⚠️ BottleneckJavaScript Execution and Layout when many components re-render unnecessarily
Core Web Vital Affected
INP
This affects how efficiently the UI updates when reactive state changes, impacting interaction responsiveness and rendering speed.
Optimization Tips
1Avoid sharing a single reactive object across many components in composables.
2Create reactive state inside composables so each component has its own instance.
3Minimize reactive dependencies to reduce re-render scope and improve responsiveness.
Performance Quiz - 3 Questions
Test your performance knowledge
What is a performance risk of sharing a single reactive state object across many components in a Vue composable?
AThe state becomes immutable and cannot update.
BAll components re-render on any state change, causing slow input responsiveness.
CThe browser caches the state, improving performance.
DComponents stop reacting to state changes.
DevTools: Performance
How to check: Record a performance profile while interacting with components using the composable. Look for long scripting times and many style/layout recalculations.
What to look for: High scripting time and multiple layout recalculations indicate inefficient reactive state causing excessive re-renders.

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