📋 Cheat Sheets

Vue.js Cheat Sheet — Composition API, Reactivity, and Components


Click any item to expand the explanation and examples.

⚡ Reactivity

ref() — reactive primitive reactivity
<script setup>
import { ref } from 'vue'

const count = ref(0)
const name = ref('Alice')

// Access/modify with .value in script
count.value++
console.log(count.value)
</script>

<template>
  <!-- No .value needed in template -->
  <p>{{ count }}</p>
  <button @click="count++">+1</button>
</template>
reactive() — reactive object reactivity
<script setup>
import { reactive } from 'vue'

const state = reactive({
  count: 0,
  user: { name: 'Alice' }
})

// No .value needed
state.count++
state.user.name = 'Bob'
</script>

Use ref() for primitives, reactive() for objects. When in doubt, use ref().

computed() — derived values reactivity
<script setup>
import { ref, computed } from 'vue'

const items = ref([1, 2, 3, 4, 5])
const total = computed(() => items.value.reduce((a, b) => a + b, 0))
const even = computed(() => items.value.filter(n => n % 2 === 0))
</script>

<template>
  <p>Total: {{ total }}</p>
</template>
watch() / watchEffect() reactivity
<script setup>
import { ref, watch, watchEffect } from 'vue'

const query = ref('')

// Watch specific ref
watch(query, (newVal, oldVal) => {
  console.log(`Changed from ${oldVal} to ${newVal}`)
})

// Watch multiple
watch([firstName, lastName], ([first, last]) => {
  console.log(`${first} ${last}`)
})

// Auto-track dependencies
watchEffect(() => {
  console.log('Query is:', query.value)
})
</script>

🧩 Components

Props and emits components
<!-- ChildComponent.vue -->
<script setup>
const props = defineProps({
  title: String,
  count: { type: Number, default: 0 }
})

const emit = defineEmits(['update', 'delete'])

function handleClick() {
  emit('update', props.count + 1)
}
</script>

<!-- Parent -->
<ChildComponent
  title="Hello"
  :count="5"
  @update="handleUpdate"
  @delete="handleDelete"
/>
v-model on components components
<!-- TextInput.vue -->
<script setup>
const model = defineModel()
</script>

<template>
  <input v-model="model" />
</template>

<!-- Parent -->
<script setup>
const name = ref('')
</script>
<TextInput v-model="name" />
Slots components
<!-- Card.vue -->
<template>
  <div class="card">
    <header><slot name="header" /></header>
    <main><slot /></main>
    <footer><slot name="footer">Default footer</slot></footer>
  </div>
</template>

<!-- Usage -->
<Card>
  <template #header><h2>Title</h2></template>
  <p>Main content goes here</p>
  <template #footer><button>Save</button></template>
</Card>

📝 Template Directives

v-if, v-for, v-show, v-bind, v-on template
<template>
  <!-- Conditional -->
  <p v-if="loggedIn">Welcome!</p>
  <p v-else-if="loading">Loading...</p>
  <p v-else>Please log in</p>

  <!-- Show/hide (CSS display toggle) -->
  <p v-show="visible">I toggle with CSS</p>

  <!-- Loop -->
  <li v-for="item in items" :key="item.id">{{ item.name }}</li>

  <!-- Bind attribute -->
  <img :src="imageUrl" :alt="imageAlt" />
  <div :class="{ active: isActive, highlight: score > 90 }" />

  <!-- Events -->
  <button @click="handleClick">Click</button>
  <form @submit.prevent="handleSubmit">...</form>
  <input @keyup.enter="search" />
</template>

🔄 Lifecycle

onMounted, onUnmounted, etc. lifecycle
<script setup>
import { onMounted, onUnmounted, onUpdated } from 'vue'

onMounted(() => {
  console.log('Component mounted')
  window.addEventListener('resize', handleResize)
})

onUnmounted(() => {
  window.removeEventListener('resize', handleResize)
})

onUpdated(() => {
  console.log('DOM updated')
})
</script>

See also: Tailwind CSS cheat sheet | TypeScript cheat sheet