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>
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
---
|
||||
title: Use shallowRef for Large Objects and External Data
|
||||
impact: MEDIUM
|
||||
impactDescription: Deep reactivity on large objects causes performance overhead - shallowRef only tracks .value changes
|
||||
type: efficiency
|
||||
tags: [vue3, reactivity, shallowRef, performance, optimization]
|
||||
---
|
||||
|
||||
# Use shallowRef for Large Objects and External Data
|
||||
|
||||
**Impact: MEDIUM** - By default, `ref()` makes objects deeply reactive, wrapping all nested properties in Proxies. For large data structures, external libraries, or immutable data, this causes unnecessary overhead. Use `shallowRef()` to only track `.value` changes.
|
||||
|
||||
`shallowRef()` is ideal for large datasets from APIs, class instances, DOM nodes, or objects managed by external libraries. Vue only tracks when `.value` is replaced, not internal mutations, significantly reducing reactivity overhead.
|
||||
|
||||
## Task Checklist
|
||||
|
||||
- [ ] Use `shallowRef()` for large API response data that won't be mutated
|
||||
- [ ] Use `shallowRef()` for external library objects (maps, charts, etc.)
|
||||
- [ ] Use `shallowRef()` for class instances with their own state management
|
||||
- [ ] Use `markRaw()` for objects that should never be reactive (e.g., third-party instances)
|
||||
- [ ] Remember: with shallowRef, you must replace `.value` entirely to trigger updates
|
||||
|
||||
**Incorrect:**
|
||||
```javascript
|
||||
import { ref } from 'vue'
|
||||
|
||||
// INEFFICIENT: Deep reactivity on large dataset
|
||||
const users = ref(await fetchUsers()) // 10,000 users, each deeply reactive
|
||||
|
||||
// INEFFICIENT: External library wrapped in Proxy
|
||||
const mapInstance = ref(new mapboxgl.Map({ /* ... */ }))
|
||||
|
||||
// INEFFICIENT: Large immutable API response
|
||||
const apiResponse = ref(await fetch('/api/big-data').then(r => r.json()))
|
||||
```
|
||||
|
||||
**Correct:**
|
||||
```javascript
|
||||
import { shallowRef, markRaw, triggerRef } from 'vue'
|
||||
|
||||
// EFFICIENT: Only .value replacement is tracked
|
||||
const users = shallowRef(await fetchUsers())
|
||||
|
||||
// Update by replacing the entire array
|
||||
users.value = await fetchUsers()
|
||||
|
||||
// If you mutate and need to trigger update, use triggerRef
|
||||
users.value.push(newUser)
|
||||
triggerRef(users) // Manually trigger watchers
|
||||
|
||||
// EFFICIENT: External library object
|
||||
const mapInstance = shallowRef(null)
|
||||
onMounted(() => {
|
||||
mapInstance.value = new mapboxgl.Map({ /* ... */ })
|
||||
})
|
||||
|
||||
// BEST for objects that should NEVER be reactive
|
||||
const thirdPartyLib = markRaw(new SomeLibrary())
|
||||
// This object won't be wrapped in Proxy even if used in reactive()
|
||||
```
|
||||
|
||||
```vue
|
||||
<script setup>
|
||||
import { shallowRef } from 'vue'
|
||||
|
||||
// Large paginated data - only care when page changes
|
||||
const pageData = shallowRef([])
|
||||
|
||||
async function loadPage(page) {
|
||||
// Replace entirely to trigger reactivity
|
||||
pageData.value = await api.getPage(page)
|
||||
}
|
||||
|
||||
// Template still works - shallowRef unwraps in template
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-for="item in pageData" :key="item.id">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
```javascript
|
||||
// Comparison: ref() vs shallowRef()
|
||||
|
||||
// With ref(): Vue wraps EVERY nested property
|
||||
const deep = ref({
|
||||
level1: {
|
||||
level2: {
|
||||
level3: { value: 1 }
|
||||
}
|
||||
}
|
||||
})
|
||||
deep.value.level1.level2.level3.value++ // Tracked!
|
||||
|
||||
// With shallowRef(): Only .value is tracked
|
||||
const shallow = shallowRef({
|
||||
level1: {
|
||||
level2: {
|
||||
level3: { value: 1 }
|
||||
}
|
||||
}
|
||||
})
|
||||
shallow.value.level1.level2.level3.value++ // NOT tracked!
|
||||
shallow.value = { /* new object */ } // Tracked!
|
||||
```
|
||||
|
||||
## Reference
|
||||
- [Vue.js Reactivity Fundamentals - Reducing Reactivity Overhead](https://vuejs.org/guide/best-practices/performance.html#reduce-reactivity-overhead-for-large-immutable-structures)
|
||||
- [Vue.js shallowRef API](https://vuejs.org/api/reactivity-advanced.html#shallowref)
|
||||
- [Vue.js markRaw API](https://vuejs.org/api/reactivity-advanced.html#markraw)
|
||||
Reference in New Issue
Block a user