askesis

Vue essentials: 50 cards on the Composition API, reactivity and Pinia

Vue 3 fundamentals: ref vs reactive, computed and watch, props and emits, v-model, directives, slots, single-file components and Pinia stores.

Web developmentBeginner50 cardsFree

Practice now

Study without an account

0 of 50 seen0 graduated
What is the Composition API?

Scheduled with the default Askesis timings. Progress is saved in this browser.

All 50 cards

  1. 1
    What is the Composition API?
    Writing component logic with imported functions like ref, computed and watch, instead of the Options API’s data, methods and computed options
    Vue 3 supports both; the Composition API makes logic easier to reuse and to type.
  2. 2
    What does <script setup> do?
    Compile-time sugar for the Composition API: variables, functions and imports declared at its top level are usable directly in the template
  3. 3
    What does ref() return?
    A reactive object holding the value in .value; reading .value tracks it, writing it triggers updates
    ts
    const count = ref(0)
    count.value++
  4. 4
    Why don’t you write .value in templates?
    Top-level refs are unwrapped automatically in the template, so {{ count }} reads count.value
  5. 5
    ref() vs reactive()
    reactive() makes an object deeply reactive through a Proxy, with no .value, but only works on objects, arrays, Maps and Sets; ref() holds any value
    The Vue docs recommend ref() as the default.
  6. 6
    Why does count stop updating?
    ts
    const state = reactive({ count: 0 })
    let { count } = state
    Destructuring copies the current value into a plain variable, disconnected from the proxy. Keep using state.count, or destructure toRefs(state)
  7. 7
    Why shouldn’t you replace a whole reactive() object?
    The template and watchers track the original proxy; assigning a new object breaks that link. Mutate its properties, or use a ref and assign .value
  8. 8
    What does computed() do?
    Returns a read-only ref whose getter result is cached and only recomputed when one of its reactive dependencies changes
    ts
    const fullName = computed(() => first.value + " " + last.value)
  9. 9
    A computed property vs a method called in the template
    A computed value is cached until its dependencies change; a method runs again on every re-render
  10. 10
    What should a computed getter never do?
    Cause side effects: no mutating other state, async requests or DOM changes. Use a watcher for those
  11. 11
    watch vs watchEffect
    watch is lazy, watches explicit sources and passes new and old values; watchEffect runs immediately and tracks whatever reactive state it reads
  12. 12
    Why doesn’t this watcher work?
    ts
    const state = reactive({ count: 0 })
    watch(state.count, (n) => console.log(n))
    state.count passes a plain number, not a reactive source. Pass a getter: watch(() => state.count, …)
  13. 13
    What do the immediate and deep watch options do?
    immediate: true also runs the callback once right away; deep: true fires on nested mutations too
    Watching a reactive() object directly is deep automatically.
  14. 14
    How do you stop a watcher?
    Call the function that watch or watchEffect returns; watchers created synchronously in setup stop automatically on unmount
  15. 15
    Declare typed props in <script setup>
    ts
    const props = defineProps<{
      title: string
      count?: number
    }>()
    defineProps is a compiler macro, so it needs no import.
  16. 16
    Can a child component change a prop?
    No. Props flow one way, parent to child, and Vue warns on mutation; emit an event or copy the value into a local ref
  17. 17
    Is destructuring defineProps() reactive?
    Since Vue 3.5, yes: the compiler rewrites title to props.title. To watch one, pass a getter: watch(() => title, …)
    Before 3.5, destructured props lost reactivity.
  18. 18
    Declare and emit an event in <script setup>
    ts
    const emit = defineEmits<{ change: [id: number] }>()
    
    emit("change", 42)
    The parent listens with <Item @change="onChange" />.
  19. 19
    What is @ in @click="save"?
    Shorthand for v-on:, which listens to DOM events or component events
  20. 20
    What is : in :src="url"?
    Shorthand for v-bind:, which binds an attribute or prop to a JavaScript expression
    Since Vue 3.4, :src alone means :src="src".
  21. 21
    What does v-model do on an <input>?
    Two-way binding: it sets the input’s value and updates the variable on every input event
  22. 22
    What does v-model expand to on a component?
    A modelValue prop plus a listener for the update:modelValue event
    html
    <Search v-model="query" />
    <!-- is short for -->
    <Search :modelValue="query" @update:modelValue="query = $event" />
  23. 23
    What does defineModel() do?
    Since Vue 3.4, it declares the v-model prop and event for you and returns a ref; assigning to it updates the parent
    ts
    const model = defineModel<string>()
    model.value = "new text"
  24. 24
    v-model modifiers .lazy, .number, .trim
    .lazy syncs on change instead of input; .number casts the value to a number; .trim strips surrounding whitespace
  25. 25
    v-if vs v-show
    v-if creates and destroys the element; v-show always renders it and toggles CSS display
    Prefer v-show for things toggled often, v-if for conditions that rarely change.
  26. 26
    Render a list with v-for
    html
    <li v-for="todo in todos" :key="todo.id">
      {{ todo.text }}
    </li>
    Use a stable unique key, not the index, when items can be reordered or removed.
  27. 27
    What happens with v-if and v-for on the same element?
    In Vue 3, v-if is evaluated first, so it can’t see the loop variable. Filter with a computed, or move v-for to a wrapping <template>
    Vue 2 had the opposite priority.
  28. 28
    What does this render?
    html
    <span v-for="n in 3">{{ n }}</span>
    Three spans containing 1, 2 and 3: a number range in v-for starts at 1, not 0
  29. 29
    What do .prevent and .stop do on an event?
    .prevent calls event.preventDefault(); .stop calls event.stopPropagation()
    Example: @submit.prevent="send". Key modifiers work too: @keyup.enter="send".
  30. 30
    Why is v-html risky?
    It inserts raw HTML, so user-supplied content can inject scripts (XSS); {{ }} interpolation always escapes text
  31. 31
    Toggle classes with :class
    html
    <div :class="{ active: isActive, 'text-error': hasError }"></div>
    Arrays work too: :class="[base, { active: isActive }]".
  32. 32
    What can go inside {{ }}?
    A single JavaScript expression, like ok ? "Yes" : "No"; statements such as if or let aren’t allowed
  33. 33
    Default and named slots
    html
    <!-- Card.vue -->
    <header><slot name="header" /></header>
    <slot>Fallback content</slot>
    
    <!-- Parent -->
    <Card>
      <template #header>Title</template>
      Body text
    </Card>
    #header is shorthand for v-slot:header.
  34. 34
    What is a scoped slot?
    A slot that passes data from the child back to the parent’s slot content
    html
    <!-- List.vue -->
    <slot :item="item" />
    
    <!-- Parent -->
    <List v-slot="{ item }">{{ item.name }}</List>
  35. 35
    What goes in a single-file component (.vue file)?
    A <template>, a <script> or <script setup> block and optional <style> blocks, compiled by a build tool such as Vite
  36. 36
    What does <style scoped> do?
    The compiler adds a data-v-… attribute to the component’s elements and rewrites its selectors, so the CSS applies only to this component
    A child component’s root element is still styled by the parent’s scoped CSS.
  37. 37
    Which lifecycle hook is the first that can access the DOM?
    onMounted; undo timers and listeners in onUnmounted
  38. 38
    Get a reference to a DOM element
    ts
    // template: <input ref="search" />
    const search = useTemplateRef<HTMLInputElement>("search")
    onMounted(() => search.value?.focus())
    useTemplateRef is Vue 3.5+; before that, declare const search = ref(null) with the same name. It is null until mounted.
  39. 39
    What is nextTick() for?
    Waiting until Vue has applied pending DOM updates after a state change: await nextTick()
    Vue batches DOM updates and applies them asynchronously.
  40. 40
    What are provide and inject?
    A way for an ancestor to pass data to any descendant without prop drilling
    ts
    provide("theme", theme)                // in an ancestor
    const theme = inject("theme", "light")  // in a descendant, with a default
  41. 41
    What is a composable?
    A function, named useSomething by convention, that uses the Composition API to package and reuse stateful logic
    ts
    export function useCounter() {
      const count = ref(0)
      const inc = () => count.value++
      return { count, inc }
    }
  42. 42
    Why can’t a parent call a <script setup> child’s function through a template ref?
    <script setup> components are closed by default; the child must list what it shares with defineExpose({ reset })
  43. 43
    What is attribute fallthrough?
    Attributes and listeners not declared as props or emits, like class, style and id, are added to the component’s root element
    Turn it off with defineOptions({ inheritAttrs: false }) and read them with useAttrs().
  44. 44
    Create and mount a Vue 3 app with Pinia
    ts
    const app = createApp(App)
    app.use(createPinia())
    app.mount("#app")
  45. 45
    What is Pinia?
    Vue’s official state management library and the successor to Vuex: stores with state, getters and actions, fully typed and devtools-friendly
  46. 46
    Define a Pinia setup store
    ts
    export const useCartStore = defineStore("cart", () => {
      const items = ref<Item[]>([])
      const count = computed(() => items.value.length)
      function add(item: Item) {
        items.value.push(item)
      }
      return { items, count, add }
    })
    Refs become state, computeds become getters, functions become actions. Return every piece of state.
  47. 47
    Why doesn’t count update?
    ts
    const store = useCounterStore()
    const { count } = store
    Destructuring a store breaks reactivity. Use const { count } = storeToRefs(store); actions can be destructured directly
  48. 48
    How does Vue 3 track reactivity?
    With JavaScript Proxies for reactive() and getters/setters for ref(); effects record what they read and re-run when it changes
    That is why adding a new property or setting an array index is reactive in Vue 3, unlike Vue 2.
  49. 49
    What does shallowRef() do?
    Only assigning .value is reactive; changes inside the value aren’t tracked. Useful for large or external objects
  50. 50
    What does <Teleport to="body"> do?
    Renders its content into another DOM node, such as body, while it stays logically part of the component; handy for modals

Frequently asked questions

Does this deck use the Options API or the Composition API?

The Composition API with script setup, which is what the Vue docs and most new projects use. The concepts behind directives, props and slots are the same in both.

Which Vue version does it cover?

Vue 3, including newer additions such as defineModel (3.4), reactive props destructure and useTemplateRef (3.5).

Should I use ref or reactive?

The Vue docs recommend ref as the default: it works with any value and survives destructuring and reassignment. reactive is fine for objects you only mutate in place.

Is Pinia required?

No. Small apps can share state with composables or provide and inject. Pinia adds devtools support, SSR safety and a consistent structure for larger apps.