Vue 3 Composition API: Refresher Cheatsheet
🔁 Reactivity
Purpose | Use | Example |
---|---|---|
Reactive primitive | ref() | const count = ref(0) → access with count.value |
Reactive object/array | reactive() | const user = reactive({ name: "Tom" }) |
Read a prop | defineProps() | const props = defineProps() |
Emit event | defineEmits() | const emit = defineEmits() |
📦 Props + Emits
<script setup>
const props = defineProps(["someValue"]);
const emit = defineEmits(["updated"]);
function updateValue() {
emit("updated", newValue);
}
</script>
<!-- Parent -->
<MyComp :some-value="val" @updated="val = $event" />
👁️ Watching
watch(
() => props.userId,
(newVal, oldVal) => {
console.log("Changed!", newVal);
},
{ immediate: true, deep: true }
);
immediate: true
: run once on mountdeep: true
: works for nested objects
🧬 Lifecycle Hooks
onMounted(() => console.log("Mounted!"));
onUpdated(() => console.log("Re-rendered!"));
onUnmounted(() => cleanupSomething());
🔄 ref
vs reactive
// ✅ ref for numbers, strings, booleans, etc.
const name = ref("Alice");
name.value = "Bob";
// ✅ reactive for objects/arrays
const user = reactive({ name: "Alice" });
user.name = "Bob";
// ❗ Can't destructure reactive() — breaks reactivity
const { name } = reactive({ name: "Alice" }); // ❌ don't do this
🧩 Template bindings
<template>
<input v-model="name" />
<p>{{ name }}</p>
</template>
<script setup>
const name = ref("Thomas");
</script>
🛠 Quick Utility Tip
import { toRefs } from "vue";
const state = reactive({ a: 1, b: 2 });
const { a, b } = toRefs(state); // now both are refs
🔍 Debug tip
watchEffect(() => {
console.log("any dep changed!", someReactiveThing);
});