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>
163 lines
3.9 KiB
Markdown
163 lines
3.9 KiB
Markdown
---
|
|
title: Avoid Deep Watchers on Large Data Structures
|
|
impact: HIGH
|
|
impactDescription: Deep watchers traverse all nested properties on every change, causing severe performance degradation
|
|
type: efficiency
|
|
tags: [vue3, watch, watchers, deep, performance, optimization]
|
|
---
|
|
|
|
# Avoid Deep Watchers on Large Data Structures
|
|
|
|
**Impact: HIGH** - Deep watchers must traverse all nested properties in the watched object on every mutation. On large data structures, this causes significant performance overhead and can lead to application slowdowns.
|
|
|
|
Use deep watchers sparingly and only when necessary. Prefer watching specific properties or using `watchEffect` which only tracks actually-used dependencies.
|
|
|
|
## Task Checklist
|
|
|
|
- [ ] Avoid `{ deep: true }` on objects with many nested properties
|
|
- [ ] Watch specific properties instead of entire objects when possible
|
|
- [ ] Consider `watchEffect` as an alternative for complex nested structures
|
|
- [ ] In Vue 3.5+, use `deep: number` to limit traversal depth
|
|
- [ ] Profile performance if deep watching is unavoidable
|
|
|
|
**Incorrect:**
|
|
```javascript
|
|
import { reactive, watch } from 'vue'
|
|
|
|
// Large data structure with many nested properties
|
|
const state = reactive({
|
|
users: [], // Could contain thousands of user objects
|
|
products: [], // Each with nested variants, images, etc.
|
|
settings: { /* deeply nested config */ }
|
|
})
|
|
|
|
// BAD: Traverses entire state tree on every change
|
|
watch(
|
|
state,
|
|
(newState) => {
|
|
console.log('State changed')
|
|
},
|
|
{ deep: true }
|
|
)
|
|
|
|
// BAD: Deep watching a large array
|
|
watch(
|
|
() => state.users,
|
|
(users) => {
|
|
updateUserList(users)
|
|
},
|
|
{ deep: true } // Expensive for large arrays!
|
|
)
|
|
```
|
|
|
|
**Correct:**
|
|
```javascript
|
|
import { reactive, watch, watchEffect } from 'vue'
|
|
|
|
const state = reactive({
|
|
users: [],
|
|
products: [],
|
|
selectedUserId: null
|
|
})
|
|
|
|
// GOOD: Watch specific property instead of entire object
|
|
watch(
|
|
() => state.selectedUserId,
|
|
(userId) => {
|
|
loadUserDetails(userId)
|
|
}
|
|
)
|
|
|
|
// GOOD: Watch array length for additions/removals
|
|
watch(
|
|
() => state.users.length,
|
|
(newLength, oldLength) => {
|
|
console.log(`Users count changed: ${oldLength} -> ${newLength}`)
|
|
}
|
|
)
|
|
|
|
// GOOD: Watch a specific computed value
|
|
watch(
|
|
() => state.users.filter(u => u.active).length,
|
|
(activeCount) => {
|
|
updateActiveUserCount(activeCount)
|
|
}
|
|
)
|
|
|
|
// GOOD: Use watchEffect for specific dependencies
|
|
watchEffect(() => {
|
|
// Only tracks properties actually accessed
|
|
const user = state.users.find(u => u.id === state.selectedUserId)
|
|
if (user) {
|
|
displayUserName(user.name)
|
|
}
|
|
})
|
|
```
|
|
|
|
## Vue 3.5+ Deep Depth Limit
|
|
|
|
```javascript
|
|
// Vue 3.5+ allows limiting traversal depth
|
|
watch(
|
|
state,
|
|
(newState) => {
|
|
console.log('Shallow nested change detected')
|
|
},
|
|
{ deep: 2 } // Only traverse 2 levels deep
|
|
)
|
|
```
|
|
|
|
## Implicit Deep Watching on Reactive Objects
|
|
|
|
```javascript
|
|
import { reactive, watch } from 'vue'
|
|
|
|
const obj = reactive({ nested: { count: 0 } })
|
|
|
|
// Direct reactive object watch = implicit deep watcher
|
|
// This is automatic but has the same performance implications
|
|
watch(obj, (newObj) => {
|
|
// Fires on any nested mutation
|
|
// Consider if you really need this
|
|
})
|
|
|
|
// BETTER: Watch only what you need
|
|
watch(
|
|
() => obj.nested.count,
|
|
(count) => {
|
|
console.log(`Count: ${count}`)
|
|
}
|
|
)
|
|
```
|
|
|
|
## watchEffect vs Deep Watch
|
|
|
|
```javascript
|
|
import { reactive, watch, watchEffect } from 'vue'
|
|
|
|
const state = reactive({
|
|
config: {
|
|
theme: 'dark',
|
|
language: 'en',
|
|
// ... many other nested properties
|
|
}
|
|
})
|
|
|
|
// BAD: Deep watch tracks ALL properties
|
|
watch(
|
|
() => state.config,
|
|
() => applyConfig(),
|
|
{ deep: true }
|
|
)
|
|
|
|
// BETTER: watchEffect only tracks what's used
|
|
watchEffect(() => {
|
|
// Only re-runs when theme or language changes
|
|
document.body.className = state.config.theme
|
|
setLocale(state.config.language)
|
|
})
|
|
```
|
|
|
|
## Reference
|
|
- [Vue.js Watchers - Deep Watchers](https://vuejs.org/guide/essentials/watchers.html#deep-watchers)
|