Vue Methods vs. Computed Properties: The Complete Performance and Debugging Guide

Posted on Sep 23, 2025

Every Vue developer faces this choice: use a method or a computed property? The wrong pick can kill performance, trigger console errors, or leave your UI stale. Here’s how to choose—and how to debug the most common pitfalls.

Real-World Pitfalls and Their Console Errors

1. Computed Not Updating

Symptoms:

  • The value shown in the template never changes.
  • No errors thrown—just stale UI.

Console Warning (Vue 3 internal):

[Vue warn]: Computed getter “filteredItems” has no effect.

Broken Example:

<script setup>
import { ref, computed } from 'vue'
const items = ref([{ id:1, active:true }, { id:2,active:false }])
let filterActive = true             // NOT reactive!
const filteredItems = computed(() => {
  return items.value.filter(i => i.active === filterActive)
})
</script>

<template>
  <button @click="filterActive = !filterActive">Toggle</button>
  <div v-for="i in filteredItems" :key="i.id">{{ i.id }}</div>
</template>

Fix: Make filterActive reactive.

const filterActive = ref(true)

2. “Cannot Read Property of Undefined” in Computed

Symptoms:

  • Console error:
    TypeError: Cannot read property 'name' of undefined
    
  • Happens when props or data are null/undefined on first render.

Broken Example:

<script setup>
const props = defineProps({ user: Object })
const displayName = computed(() => props.user.name.toUpperCase())
</script>

Fix: Guard against missing data.

const displayName = computed(() => {
  return props.user && props.user.name
    ? props.user.name.toUpperCase()
    : 'Guest'
})

3. Methods Causing Hidden Re-Renders

Symptoms:

  • Console not warning, but performance profiler shows excessive renders.
  • Every unrelated data change triggers the method.

Example:

<script setup>
import { ref } from 'vue'
const user = ref({ name: 'Alice' })
const counter = ref(0)

const getNameLength = () => {
  console.log('Calculating length')
  return user.value.name.length
}
</script>

<template>
  <p>{{ getNameLength() }}</p>
  <button @click="counter++">Increment {{ counter }}</button>
</template>

Each click logs “Calculating length”, even though user.name didn’t change.

Solution: Move to computed.

const nameLength = computed(() => user.value.name.length)

4. “Methods vs Computed” TypeError in Template

Symptoms:

  • Console error:
    TypeError: _ctx.getFullName is not a function
    
  • Occurs when you mistakenly call a method not defined in setup.

Broken Example:

<template>
  <p>{{ getFullName() }}</p>
</template>

<script setup>
const fullName = computed(() => 'John Doe')
// Oops: no getFullName defined
</script>

Fix: Either define getFullName or call the computed:

<p>{{ fullName }}</p>

or

const getFullName = () => fullName.value

5. Computed Cache Invalidation Issues

Symptoms:

  • Computed doesn’t recalculate when nested properties change.
  • No console errors—just stale results.

Broken Example:

const settings = reactive({ theme: { color: 'dark' } })
const color = computed(() => settings.theme.color)

// Later:
settings.theme = { color: 'light' } // computed updates
settings.theme.color = 'blue'       // computed ignores this change!

Fix: Use deep reactivity or toRefs on nested objects:

const theme = toRefs(settings.theme)
const color = computed(() => theme.color.value)

New Example: Handling Error-Prone Calculations

Scenario: You have a list of items whose price can be null or a number. You need the total, but null prices break the computed.

Broken Computed:

const items = ref([{ price: 10 }, { price: null }])
const total = computed(() => {
  return items.value.reduce((sum, i) => sum + i.price, 0)
})
// TypeError: Cannot read property 'price' of null

Robust Fix:

const total = computed(() =>
  items.value.reduce((sum, i) => {
    const price = Number(i.price) || 0
    return sum + price
  }, 0)
)

And if you accidentally destructure items, you lose reactivity:

const { value: localItems } = items  // BAD

Always access items.value directly or use a computed wrapper.

The Rules at a Glance

  • Computed properties
    • Cache results until dependencies change
    • Only track dependencies accessed during execution
    • Guard against undefined inputs
  • Methods
    • Run on every render
    • Accept parameters
    • Perform side effects

Master these patterns, handle the console errors, and your Vue components will be bulletproof, high-performance, and maintainable.