⏱️ Estimated read: 6 min
|
|
A quick-reference for Vue 3 APIs, reactivity, components, and internals. Organized for lookup, not for reading.
Component Definition
| Syntax | Meaning |
|---|
<script setup> | Composition API, compiled to setup() |
defineComponent({}) | Options API with TS support |
export default {} | Options API object |
<script setup lang="ts"> | TypeScript + Composition API |
<script setup vapor> | Vapor Mode component (Vue 3.6+) |
Reactivity: Core
| Function | Purpose |
|---|
ref(v) | Reactive wrapper, access via .value |
reactive(obj) | Deep reactive proxy |
shallowRef(v) | Only .value reactive |
shallowReactive(obj) | Only root props reactive |
computed(fn) | Cached derived value |
readonly(obj) | Read-only proxy |
shallowReadonly(obj) | Shallow read-only |
markRaw(obj) | Never proxy this object |
toRaw(proxy) | Get original object |
isRef(v) | Type guard for refs |
isReactive(v) | Check for reactive proxy |
isReadonly(v) | Check for readonly proxy |
unref(v) | Unwrap ref, otherwise return value |
toRef(obj, key) | Synced ref to a property |
toRef(() => expr) | Read-only ref from getter (3.3+) |
toRefs(obj) | Synced refs for all props |
customRef(factory) | Manual track/trigger |
triggerRef(ref) | Force update on a shallow ref |
Reactivity: Effects
| Function | Purpose |
|---|
watchEffect(fn) | Run fn, track deps, re-run on change |
watch(src, cb) | Explicit source watching |
watchPostEffect(fn) | After DOM update |
watchSyncEffect(fn) | Synchronous |
effectScope() | Group effects |
scope.run(fn) | Run fn, capture effects |
scope.stop() | Stop all captured effects |
onScopeDispose(fn) | Cleanup on scope stop |
getCurrentScope() | Current active scope |
stop(handle) | Stop a watch |
Watch Options
| Option | Effect |
|---|
immediate: true | Run callback on creation |
deep: true | Watch nested mutations |
flush: 'pre' | Before DOM update (default) |
flush: 'post' | After DOM update |
flush: 'sync' | Synchronously |
once: true | Run once, then stop (3.4+) |
watch(source, (newVal, oldVal) => {}, {
immediate: true,
deep: true,
flush: 'post',
})
Component Lifecycle
| Hook | When |
|---|
onBeforeMount | Before DOM mount |
onMounted | After DOM mount |
onBeforeUpdate | Before re-render |
onUpdated | After re-render |
onBeforeUnmount | Before unmount |
onUnmounted | After unmount |
onActivated | Inside <KeepAlive> shown |
onDeactivated | Inside <KeepAlive> hidden |
onErrorCaptured | Descendant error |
onRenderTracked | Dev: reactive dep tracked |
onRenderTriggered | Dev: reactive dep triggered |
Component APIs
| Function | Purpose |
|---|
defineProps() | Declare props |
defineEmits() | Declare emits |
defineExpose() | Expose public instance |
defineModel() | Two-way prop (3.4+) |
defineOptions() | Component options (3.3+) |
defineSlots() | Typed slots (3.3+) |
useSlots() | Access slots |
useAttrs() | Access fallthrough attrs |
useTemplateRef() | Template ref (3.5+) |
useId() | Unique ID (3.5+) |
getCurrentInstance() | Component instance (null in Vapor) |
nextTick() | Wait for DOM flush |
useModel() | Custom model logic (3.4+) |
Props & Emits
// Props
const props = defineProps<{ title: string; count?: number }>()
// Props with defaults (3.5+)
const { title, count = 0 } = defineProps<{ title: string; count?: number }>()
// Emits
const emit = defineEmits<{
change: [value: string]
close: []
}>()
// Model
const model = defineModel<string>()
Template Syntax
| Directive | Purpose |
|---|
v-if / v-else-if / v-else | Conditional |
v-show | Toggle display |
v-for | Loop |
v-on / @ | Event |
v-bind / : | Attribute/prop |
v-model | Two-way binding |
v-slot / # | Slot |
v-html | Raw HTML |
v-text | Text content |
v-once | Render once |
v-memo | Memoize list items |
v-pre | Skip compilation |
v-for Key
<li v-for="item in items" :key="item.id">{{ item.name }}</li>
Always use a stable unique key. Never use array index when order can change.
Slots
| Feature | Syntax |
|---|
| Default slot | <slot /> |
| Named slot | <slot name="header" /> |
| Scoped slot | <slot :item="item" /> |
| Consumer default | <template #default="{ item }"> |
| Consumer named | <template #header> |
| Dynamic slot | <template #[name]> |
| Fallback | <slot>Fallback</slot> |
Computed
const doubled = computed(() => count.value * 2)
// Writable computed
const fullName = computed({
get: () => `${first.value} ${last.value}`,
set: (v) => { [first.value, last.value] = v.split(' ') },
})
Provide / Inject
// Provider
provide('key', value)
provide('key', readonly(ref))
// Consumer
const value = inject('key', defaultValue)
Teleport
<Teleport to="body">
<div class="modal">...</div>
</Teleport>
Suspense
<Suspense>
<template #default><AsyncComponent /></template>
<template #fallback><Spinner /></template>
</Suspense>
KeepAlive
<KeepAlive :max="10">
<component :is="current" />
</KeepAlive>
Transitions
| Class | When |
|---|
v-enter-from | Enter start |
v-enter-active | Enter duration |
v-enter-to | Enter end |
v-leave-from | Leave start |
v-leave-active | Leave duration |
v-leave-to | Leave end |
<Transition name="fade">
<div v-if="show">Content</div>
</Transition>
Router Essentials
| API | Purpose |
|---|
useRouter() | Router instance |
useRoute() | Current route |
<RouterLink> | Link |
<RouterView> | Route outlet |
router.push() | Navigate |
router.replace() | Navigate without history |
beforeEach | Global guard |
// Route definition
const routes = [
{ path: '/', component: Home },
{ path: '/user/:id', component: User, props: true },
]
Pinia Essentials
import { defineStore } from 'pinia'
export const useCounter = defineStore('counter', {
state: () => ({ count: 0 }),
getters: {
double: (state) => state.count * 2,
},
actions: {
increment() { this.count++ },
},
})
| API | Purpose |
|---|
defineStore(id, options) | Define store |
storeToRefs(store) | Destructure preserving reactivity |
store.$patch({}) | Partial update |
store.$reset() | Reset to initial state |
Compiler Macros
| Macro | Purpose |
|---|
defineProps | Props declaration |
defineEmits | Emits declaration |
defineExpose | Public API |
defineModel | Two-way binding |
defineOptions | Component options |
defineSlots | Typed slots |
Macros are compiled away; they have no runtime existence. Do not import them.
Compiler Optimizations
| Optimization | Effect |
|---|
| Static Hoisting | Static VNodes created once |
| Patch Flags | Bitmask of dynamic properties |
| Tree Flattening | dynamicChildren array |
| Block Tree | Structural directives create blocks |
Patch Flags
| Flag | Value |
|---|
TEXT | 1 |
CLASS | 2 |
STYLE | 4 |
PROPS | 8 |
FULL_PROPS | 16 |
HOISTED | -1 |
BAIL | -2 |
Internals: Reactivity
| Concept | Detail |
|---|
track | Record effect against property (in get) |
trigger | Schedule effects (in set) |
| Target map | WeakMap → deps map → dep set |
| EffectScope | Boundary for cleanup |
| Orphaned effects | Created outside scope, never stopped |
Internals: Scheduler
| Concept | Detail |
|---|
queueJob | Push update into queue |
flushJobs | Run queue, sorted by uid |
| Microtask | Promise.resolve().then(flushJobs) |
| Parent first | Smaller uid runs first |
nextTick | Returns flush promise |
Internals: Mount
| Function | Purpose |
|---|
mountComponent | Entry point |
createComponentInstance | Create instance |
setupComponent | Run setup() |
setupRenderEffect | Create render effect |
renderComponentRoot | Run render function |
patch | Diff and apply |
script setup Binding Types
| Type | Template Access |
|---|
SETUP_REF | .value |
SETUP_LET | isRef(x) ? x.value : x |
SETUP_CONST | Direct |
PROPS | __props.x (inline) or $props.x |
SETUP_REACTIVE_CONST | Direct |
Vapor Mode
| Aspect | Detail |
|---|
| Opt-in | <script setup vapor> |
| Pure app | createVaporApp() |
| Mixed app | createApp().use(vaporInteropPlugin) |
| Runtime size | ~53% smaller |
| No VNode | Direct DOM operations |
| No Options API | Only <script setup> |
getCurrentInstance() | Returns null |
Performance Cheatsheet
Do
| Practice | Effect |
|---|
Stable :key in v-for | Correct DOM reuse |
shallowRef for large data | No deep proxy |
markRaw for library instances | No proxy wrapping |
v-memo for large lists | Skip unchanged items |
computed for derived state | Cached |
Cleanup in onBeforeUnmount | No leaks |
Don’t
| Anti-Pattern | Problem |
|---|
Array index as :key | Wrong DOM reuse on reorder |
ref() for large API data | Deep proxy overhead |
watchEffect after await | Orphaned effect |
v-if + v-for on same element | v-if evaluates first |
| Mutating props | Vue warns, parent state diverges |
| Deep watch on huge objects | Performance cost |
Lifecycle Cleanup Checklist
| Resource | Cleanup |
|---|
addEventListener | removeEventListener in onBeforeUnmount |
setInterval | clearInterval |
setTimeout | clearTimeout |
| Third-party instance | .destroy() |
| WebSocket | .close() |
| Observer | .disconnect() |
| Effect outside scope | onScopeDispose |
Common Gotchas
| Trap | Reality |
|---|
Destructuring reactive() | Loses reactivity; use toRefs() |
ref() vs toRef() | ref() copies; toRef() syncs |
unref() unwraps reactive | No; only refs |
watch on reactive object | Implicitly deep |
watch on ref object | Shallow by default |
computed with side effect | Pure computation only |
v-if + v-for same element | v-if has no loop scope |
v-model on prop | Use defineModel() |
defineProps destructure | Reactive in 3.5+ (compiler rewrites) |
$attrs on multi-root | Must bind explicitly |
v-html with user input | XSS risk; sanitize |
nextTick before DOM read | Required after state change |
provide with ref | Provide the ref, not .value |
One-Page Flow
COMPONENT
<script setup> → setup() → render effect → VNode → patch → DOM
REACTIVITY
ref() → track on read → trigger on write → effect queued → flush
LIFECYCLE
onMounted → onUpdated → onBeforeUnmount → onUnmounted
PERFORMANCE
computed | shallowRef | markRaw | v-memo | stable :key
CLEANUP
onBeforeUnmount → remove listeners, clear timers, destroy instances
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!