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-conditional-dependencies.md
1---2title: Ensure All Dependencies Are Accessed in Computed Properties3impact: HIGH4impactDescription: Conditional logic can prevent dependency tracking causing stale computed values5type: capability6tags: [vue3, computed, reactivity, dependency-tracking, gotcha]7---89# Ensure All Dependencies Are Accessed in Computed Properties1011**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.1213This is a subtle but common source of bugs, especially with short-circuit evaluation (`&&`, `||`) and early returns.1415## Task Checklist1617- [ ] Access all reactive dependencies before any conditional logic18- [ ] Be cautious with short-circuit operators (`&&`, `||`) that may skip property access19- [ ] Store all dependencies in variables at the start of the computed getter20- [ ] Test computed properties with different initial states2122**Incorrect:**23```vue24<script setup>25import { ref, computed } from 'vue'2627const isEnabled = ref(false)28const data = ref('important data')2930// BAD: If isEnabled is false initially, data.value is never accessed31// Vue won't track 'data' as a dependency!32const result = computed(() => {33if (!isEnabled.value) {34return 'disabled'35}36return data.value // This dependency may not be tracked37})3839// BAD: Short-circuit prevents second access40const password = ref('')41const confirmPassword = ref('')4243const isValid = computed(() => {44// If password is empty, confirmPassword is never accessed45return password.value && password.value === confirmPassword.value46})4748// BAD: Early return prevents dependency access49const user = ref(null)50const permissions = ref(['read', 'write'])5152const canEdit = computed(() => {53if (!user.value) {54return false // permissions.value never accessed when user is null55}56return permissions.value.includes('write')57})58</script>59```6061**Correct:**62```vue63<script setup>64import { ref, computed } from 'vue'6566const isEnabled = ref(false)67const data = ref('important data')6869// GOOD: Access all dependencies first70const result = computed(() => {71const enabled = isEnabled.value72const currentData = data.value // Always accessed7374if (!enabled) {75return 'disabled'76}77return currentData78})7980// GOOD: Access both values before comparison81const password = ref('')82const confirmPassword = ref('')8384const isValid = computed(() => {85const pwd = password.value86const confirm = confirmPassword.value // Always accessed8788return pwd && pwd === confirm89})9091// GOOD: Access all reactive sources upfront92const user = ref(null)93const permissions = ref(['read', 'write'])9495const canEdit = computed(() => {96const currentUser = user.value97const currentPermissions = permissions.value // Always accessed9899if (!currentUser) {100return false101}102return currentPermissions.includes('write')103})104</script>105```106107## The Dependency Tracking Mechanism108109Vue's reactivity system works by tracking which reactive properties are accessed when a computed property runs:110111```javascript112// How Vue tracks dependencies (simplified):113// 1. Start tracking114// 2. Run the getter function115// 3. Record every .value or reactive property access116// 4. Stop tracking117118const computed = computed(() => {119// Vue starts tracking here120if (conditionA.value) { // conditionA is tracked121return valueB.value // valueB is ONLY tracked if conditionA is true122}123return 'default' // If conditionA is false, valueB is NOT tracked!124})125```126127## Pattern: Destructure All Dependencies First128129```javascript130// GOOD PATTERN: Destructure/access everything at the top131const result = computed(() => {132// Access all potential dependencies133const { user, settings, items } = toRefs(store)134const userVal = user.value135const settingsVal = settings.value136const itemsVal = items.value137138// Now use conditional logic safely139if (!userVal) return []140if (!settingsVal.enabled) return []141return itemsVal.filter(i => i.active)142})143```144145## Reference146- [Vue.js Reactivity in Depth](https://vuejs.org/guide/extras/reactivity-in-depth.html)147- [GitHub Discussion: Dependency collection gotcha with conditionals](https://github.com/vuejs/Discussion/issues/15)148