The Lifecycle and onMounted
When Shelf opens, the cursor should already be blinking in the search box. You write searchInput.value.focus() in your script, and the console says "Cannot read properties of null". The input exists in your template, so why is it missing? Because your code ran before Vue had created it. Timing is what lifecycle hooks are for.
The rule
Setup runs first; the DOM exists only from
onMountedon.
Every component instance lives through the same stages:
- Setup.
<script setup>runs once. Refs, computeds and functions are created. No DOM yet. - Before mount.
onBeforeMountruns just before the elements are created and inserted. - Mounted.
onMountedruns after the component's elements are in the page. Template refs now point at real elements. - Updates. When reactive state changes, the component re-renders, with
onBeforeUpdateandonUpdatedaround it. This can happen many times. - Unmount. When the component is removed,
onBeforeUnmountand thenonUnmountedrun.
Hooks are functions you import from vue and call with a callback:
<script setup>
import { ref, onMounted } from 'vue'
const searchInput = ref(null) // filled when the element exists
onMounted(() => {
searchInput.value.focus()
})
</script>
<template>
<input ref="searchInput" type="search" placeholder="Find a book" />
</template>The ref="searchInput" attribute is a template ref: after mounting, Vue puts the real <input> element into the ref with the same name. (Vue 3.5 also offers useTemplateRef('searchInput') for the same job.) Before mounting it is null, which is exactly the error from the introduction.
Typical onMounted work: focusing an element, measuring sizes, starting a chart or map library that needs a real element, and adding listeners to window. Loading data can start earlier, right in setup, since it does not need the DOM.
One rule: register hooks synchronously during setup. Calling onMounted inside a setTimeout, or in any callback that runs later, is too late; Vue no longer knows which component the hook belongs to.
The shortcut
For any piece of setup code, ask "Does it need a real element?" Yes → put it inside onMounted. No → it can run directly in setup.
Create the books ref
Pure data, no element needed. Directly in setup.
Drills
Answer fast — trust the rule.
When does onMounted run?
In setup, searchInput.value is null. Why?
Which hook runs after a re-render caused by a state change?
Which of these registers a hook correctly?
Remember
- The stages are setup, mount, update (repeated) and unmount;
onMountedruns once the DOM exists. - Shortcut: "does it need a real element?" Yes means
onMounted. - Trap: touching template refs during setup, or registering hooks asynchronously.
