Files
agent-skills/skills/vue-best-practices/reference/computed-conditional-dependencies.md
Jason Woltje f5792c40be feat: Complete fleet — 94 skills across 10+ domains
Pulled ALL skills from 15 source repositories:
- anthropics/skills: 16 (docs, design, MCP, testing)
- obra/superpowers: 14 (TDD, debugging, agents, planning)
- coreyhaines31/marketingskills: 25 (marketing, CRO, SEO, growth)
- better-auth/skills: 5 (auth patterns)
- vercel-labs/agent-skills: 5 (React, design, Vercel)
- antfu/skills: 16 (Vue, Vite, Vitest, pnpm, Turborepo)
- Plus 13 individual skills from various repos

Mosaic Stack is not limited to coding — the Orchestrator and
subagents serve coding, business, design, marketing, writing,
logistics, analysis, and more.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 16:27:42 -06:00

148 lines
4.3 KiB
Markdown

---
title: Ensure All Dependencies Are Accessed in Computed Properties
impact: HIGH
impactDescription: Conditional logic can prevent dependency tracking causing stale computed values
type: capability
tags: [vue3, computed, reactivity, dependency-tracking, gotcha]
---
# Ensure All Dependencies Are Accessed in Computed Properties
**Impact: HIGH** - Vue tracks computed property dependencies by monitoring which reactive properties are accessed during execution. If conditional logic prevents a property from being accessed on the first run, Vue won't track it as a dependency, causing the computed property to not update when that property changes.
This is a subtle but common source of bugs, especially with short-circuit evaluation (`&&`, `||`) and early returns.
## Task Checklist
- [ ] Access all reactive dependencies before any conditional logic
- [ ] Be cautious with short-circuit operators (`&&`, `||`) that may skip property access
- [ ] Store all dependencies in variables at the start of the computed getter
- [ ] Test computed properties with different initial states
**Incorrect:**
```vue
<script setup>
import { ref, computed } from 'vue'
const isEnabled = ref(false)
const data = ref('important data')
// BAD: If isEnabled is false initially, data.value is never accessed
// Vue won't track 'data' as a dependency!
const result = computed(() => {
if (!isEnabled.value) {
return 'disabled'
}
return data.value // This dependency may not be tracked
})
// BAD: Short-circuit prevents second access
const password = ref('')
const confirmPassword = ref('')
const isValid = computed(() => {
// If password is empty, confirmPassword is never accessed
return password.value && password.value === confirmPassword.value
})
// BAD: Early return prevents dependency access
const user = ref(null)
const permissions = ref(['read', 'write'])
const canEdit = computed(() => {
if (!user.value) {
return false // permissions.value never accessed when user is null
}
return permissions.value.includes('write')
})
</script>
```
**Correct:**
```vue
<script setup>
import { ref, computed } from 'vue'
const isEnabled = ref(false)
const data = ref('important data')
// GOOD: Access all dependencies first
const result = computed(() => {
const enabled = isEnabled.value
const currentData = data.value // Always accessed
if (!enabled) {
return 'disabled'
}
return currentData
})
// GOOD: Access both values before comparison
const password = ref('')
const confirmPassword = ref('')
const isValid = computed(() => {
const pwd = password.value
const confirm = confirmPassword.value // Always accessed
return pwd && pwd === confirm
})
// GOOD: Access all reactive sources upfront
const user = ref(null)
const permissions = ref(['read', 'write'])
const canEdit = computed(() => {
const currentUser = user.value
const currentPermissions = permissions.value // Always accessed
if (!currentUser) {
return false
}
return currentPermissions.includes('write')
})
</script>
```
## The Dependency Tracking Mechanism
Vue's reactivity system works by tracking which reactive properties are accessed when a computed property runs:
```javascript
// How Vue tracks dependencies (simplified):
// 1. Start tracking
// 2. Run the getter function
// 3. Record every .value or reactive property access
// 4. Stop tracking
const computed = computed(() => {
// Vue starts tracking here
if (conditionA.value) { // conditionA is tracked
return valueB.value // valueB is ONLY tracked if conditionA is true
}
return 'default' // If conditionA is false, valueB is NOT tracked!
})
```
## Pattern: Destructure All Dependencies First
```javascript
// GOOD PATTERN: Destructure/access everything at the top
const result = computed(() => {
// Access all potential dependencies
const { user, settings, items } = toRefs(store)
const userVal = user.value
const settingsVal = settings.value
const itemsVal = items.value
// Now use conditional logic safely
if (!userVal) return []
if (!settingsVal.enabled) return []
return itemsVal.filter(i => i.active)
})
```
## Reference
- [Vue.js Reactivity in Depth](https://vuejs.org/guide/extras/reactivity-in-depth.html)
- [GitHub Discussion: Dependency collection gotcha with conditionals](https://github.com/vuejs/Discussion/issues/15)