Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Vue 3 debugging reference for reactivity issues, computed errors, watcher bugs, async failures, and SSR hydration problems.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
reference/computed-no-side-effects.md
1---2title: Computed Property Getters Must Be Side-Effect Free3impact: HIGH4impactDescription: Side effects in computed getters break reactivity and cause unpredictable behavior5type: efficiency6tags: [vue3, computed, reactivity, side-effects, best-practices]7---89# Computed Property Getters Must Be Side-Effect Free1011**Impact: HIGH** - Computed getter functions should only perform pure computation. Side effects in computed getters break Vue's reactivity model and cause bugs that are difficult to trace.1213Computed properties are designed to declaratively describe how to derive a value from other reactive state. They are not meant to perform actions or modify state.1415## Task Checklist1617- [ ] Never mutate other reactive state inside a computed getter18- [ ] Never make async requests or API calls inside a computed getter19- [ ] Never perform DOM mutations inside a computed getter20- [ ] Use watchers for reacting to state changes with side effects21- [ ] Use event handlers for user-triggered actions2223**Incorrect:**24```vue25<script setup>26import { ref, computed } from 'vue'2728const items = ref([])29const count = ref(0)30const lastFetch = ref(null)3132// BAD: Mutates other state33const doubledCount = computed(() => {34count.value++ // Side effect - modifying state!35return count.value * 236})3738// BAD: Makes async request39const userData = computed(async () => {40const response = await fetch('/api/user') // Side effect - API call!41return response.json()42})4344// BAD: Modifies DOM45const highlightedItems = computed(() => {46document.title = `${items.value.length} items` // Side effect - DOM mutation!47return items.value.filter(i => i.highlighted)48})4950// BAD: Writes to external state51const processedData = computed(() => {52lastFetch.value = new Date() // Side effect - modifying state!53return items.value.map(i => i.name)54})55</script>56```5758**Correct:**59```vue60<script setup>61import { ref, computed, watch, onMounted } from 'vue'6263const items = ref([])64const count = ref(0)65const userData = ref(null)6667// GOOD: Pure computation only68const doubledCount = computed(() => {69return count.value * 270})7172// GOOD: Use lifecycle hook for initial fetch73onMounted(async () => {74const response = await fetch('/api/user')75userData.value = await response.json()76})7778// GOOD: Pure filtering79const highlightedItems = computed(() => {80return items.value.filter(i => i.highlighted)81})8283// GOOD: Use watcher for side effects84watch(items, (newItems) => {85document.title = `${newItems.length} items`86}, { immediate: true })8788// Increment count through event handler, not computed89function increment() {90count.value++91}92</script>93```9495## What Counts as a Side Effect9697| Side Effect Type | Example | Alternative |98|-----------------|---------|-------------|99| State mutation | `otherRef.value = x` | Use watcher |100| API calls | `fetch()`, `axios()` | Use watcher or lifecycle hook |101| DOM manipulation | `document.title = x` | Use watcher |102| Console logging | `console.log()` | Remove or use watcher |103| Storage access | `localStorage.setItem()` | Use watcher |104| Timer setup | `setTimeout()` | Use lifecycle hook |105106## Reference107- [Vue.js Computed Properties - Getters Should Be Side-Effect Free](https://vuejs.org/guide/essentials/computed.html#getters-should-be-side-effect-free)108