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>
3.6 KiB
3.6 KiB
title, impact, impactDescription, type, tags
| title | impact | impactDescription | type | tags | |||||
|---|---|---|---|---|---|---|---|---|---|
| Use shallowRef for Large Objects and External Data | MEDIUM | Deep reactivity on large objects causes performance overhead - shallowRef only tracks .value changes | efficiency |
|
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
.valueentirely to trigger updates
Incorrect:
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:
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()
<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>
// 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!