Skip to content
beginner Phase 7 · Lifecycles and Composables

Lifecycle Hooks

Run setup work when the component mounts, updates, and unmounts.

40m
0 problems
Topic Progress 0%

Lifecycle Hooks: Core Concepts

Setup and mount are different moments

In Vue's Composition API, setup code runs while the component instance is being created, before its DOM exists. Use setup for synchronous state initialization, computed values, and watchers that do not need rendered elements. onMounted runs after the component's DOM has been inserted. It is the right place for work that needs an element, such as measuring layout, focusing an input, or starting an observer tied to that element.

Lifecycle hooks must be registered synchronously while Vue has an active component instance, typically at the top level of setup or script setup. Registering a hook later inside a timer or an arbitrary promise callback loses that active instance and Vue cannot reliably associate the hook with the component. If an async operation is needed, register the hook synchronously and perform async work from its callback.

Update and DOM timing

Reactive state changes trigger rendering. onUpdated runs after Vue has patched the component's DOM in response to an update. It is useful when an external library must inspect the updated DOM, but it runs after many updates and should not be the default place for derived state. Changing reactive state inside onUpdated can create an update loop. Use computed values for derived data and watchers for side effects tied to specific state changes.

If a watcher changes state and code must inspect the resulting DOM, use nextTick or a watcher flush timing that matches the requirement rather than treating onUpdated as a general callback. Keep DOM reads and writes narrow to avoid layout thrashing. Prefer template refs and component state over querying global selectors that can select another component's element.

Unmount and error handling

onUnmounted runs after a component is removed. Release resources created by the component: intervals, event listeners, observers, sockets, and external subscriptions. Vue stops setup-created render effects and watchers, but it cannot automatically clear arbitrary browser resources. Cleanup belongs with the code that acquires the resource so ownership is clear.

onErrorCaptured can catch errors from descendant rendering, setup, or lifecycle work and allow a component boundary to display a fallback. It does not replace logging or error handling in asynchronous event handlers and detached promises. Errors crossing a boundary should retain enough context to diagnose the failure without exposing sensitive data. A global app error handler can provide centralized reporting, while local boundaries keep a failing widget from taking down an entire screen.

Lifecycle differs across environments

Server-side rendering does not mount a browser DOM. DOM-dependent hooks such as onMounted and onUpdated do not run on the server, so browser APIs should not be accessed during server setup. Use client-only boundaries or defer browser work until mount. Avoid module-level mutable component state in an SSR server because modules can be shared across requests.

KeepAlive changes lifecycle expectations. A kept-alive component can be deactivated and later reactivated without being unmounted. Use onDeactivated and onActivated when a resource should pause while the view is cached and resume when it returns. A route change does not always destroy a component; understand whether the instance is reused, cached, or removed before placing cleanup logic.

Lifecycle hooks are synchronization points, not a substitute for clear ownership. Choose the narrowest hook that matches when the work is valid, register it synchronously, and clean up what the component creates.

Lifecycle Hooks: Practice

Measure an element after mount

Suppose a chart library needs a real element width. Declare a template ref and initialize the library in onMounted, when the element exists. Store the returned chart instance so it can be updated when data changes and destroyed when the component is removed. Do not initialize the chart at module scope or during SSR setup because there is no browser element there.

Use a watcher for the chart data rather than rebuilding the instance on every component update. If a size observer is registered, disconnect it during unmount. If a resize event is handled manually, remove the exact same callback reference that was added. Give the chart a stable container and ensure it does not repeatedly mutate the dimensions that trigger its own observer.

Avoid update loops

Create a small component with a value displayed in the template and log onUpdated. Change the value and observe that the hook runs after the DOM reflects it. Then add a reactive increment inside onUpdated and see why it repeats. Remove that mutation and derive any display value with computed instead. If an external library must write to the DOM, isolate its element and avoid feeding its measurements back into the same state without a comparison or stable condition.

Use nextTick when a particular event handler needs to read the DOM after a state change. For example, after adding an item to a list, wait for the patch and then focus the new item's input. This is more precise than waiting for every component update. A template ref gives direct access to the owned element without a global selector.

Handle errors at the right boundary

Add an error boundary around a chart widget so a rendering failure displays a local fallback while the rest of the page remains usable. Report the error with component context and a correlation id. Keep asynchronous fetch errors in the widget's explicit loading/error state because a promise rejection from an event handler may not be caught by a render boundary.

Verify server and cached lifecycles

Render the component in an SSR test and confirm browser APIs are not accessed during setup. Mount it in a browser test and verify the DOM-dependent hook initializes once. Unmount and confirm the observer, listener, and chart instance are released. If the route is wrapped in KeepAlive, navigate away and back: deactivation should not be mistaken for destruction. Pause expensive polling on deactivation and resume it on activation if that matches the product behavior.

Use fake timers to test interval cleanup and a controlled observer mock to test disconnection. These tests verify ownership, not just hook invocation order. Avoid asserting implementation-specific logs; assert that the user-visible result appears at the right time and that resources no longer fire after the component is gone.

Choose the smallest lifecycle surface

Before adding a hook, ask whether the behavior can be expressed as setup-time state, a computed value, a watcher, or a component event. Lifecycle callbacks are most useful at boundaries that truly depend on mount, update, activation, or teardown. A few well-placed hooks are easier to reason about than a large collection of callbacks that hide the component's behavior.

Lifecycle Hooks: Trade-offs and Interviews

Hooks can hide ownership

Lifecycle hooks are convenient, but work scattered across mounted, updated, and unmounted callbacks can make a component's behavior difficult to follow. Keep acquisition and cleanup near one another, use composables for reusable resource ownership, and avoid using onUpdated as a catch-all state synchronization mechanism. Derived values belong in computed; side effects belong in watchers or explicit event handlers.

Account for reuse and SSR

A route parameter change may reuse the same component, and KeepAlive may deactivate rather than destroy it. Cleanup that only runs on unmount will not pause work for a deactivated view. Conversely, treating every deactivation as destruction can discard state the user expects to retain. Choose behavior based on the resource and UX: a WebSocket may pause, while a cached draft may remain.

SSR setup can run without browser globals and potentially across requests. Keep request-specific state inside the component or request-scoped app factory; do not put mutable user state in a shared module singleton. Move DOM access to a client lifecycle boundary and test server rendering separately from browser mounting.

In an interview, explain setup versus mounted, why updated hooks can loop, and how unmount cleanup works. Discuss KeepAlive and SSR as cases that change assumptions. Give one example of a resource acquisition and cleanup pair. This shows lifecycle hooks are chosen for a concrete synchronization boundary, not used to compensate for unclear state flow.

Consider hook timing when coordinating parent and child components. A child's mounted hook runs before the parent's mounted hook; do not assume parent-side DOM measurements include child work that has not completed. Use explicit events or refs when coordination is required. Keep expensive work out of frequently invoked update hooks and use performance measurements before adding lifecycle complexity.

Lifecycle behavior should be tested in the environment where it matters. SSR tests reveal browser-global access during setup; browser tests reveal DOM timing and observer cleanup. A component that works in a client-only development server can still fail when rendered on the server or cached by a route layout. Include those runtime assumptions in code review when adding a hook.

For error handling, a local boundary should provide a meaningful fallback and a way to recover or retry if safe. Report component and route context, but avoid placing user data in error telemetry. The global handler can record uncaught failures while the local component keeps unrelated parts of the page available. Error boundaries do not catch every asynchronous callback, so handle promise failures and event handlers explicitly.

Test an error boundary with both a synchronous render failure and a child lifecycle failure, then verify the fallback remains usable. Also test a rejected event-handler promise separately, because a render boundary does not replace local async error handling. Include a retry path only when repeating the operation is safe. Log enough context for diagnosis without exposing user data. Verify that the fallback does not retain a broken child instance or repeat the same failing effect on every render. Run this check in both client and server-oriented test environments.

Quiz

1. Which statement about Lifecycle Hooks is accurate?

Question 1 options

2. When reviewing Lifecycle Hooks, which point must hold?

Question 2 options

3. When is onMounted appropriate?

Question 3 options

4. Why avoid changing reactive state unconditionally in onUpdated?

Question 4 options

Flashcards

Question

What is Lifecycle Hooks?

Answer

Run setup work when the component mounts, updates, and unmounts.

Question

Lifecycle Hooks: why it matters

Answer

onMounted fires after the component's DOM is inserted and is the place for subscriptions.

Question

Lifecycle Hooks: key detail

Answer

onUpdated runs after each re-render caused by reactive state changes.

Question

Lifecycle Hooks: practical note

Answer

onUnmounted fires after removal and is where listeners and timers should be released.

Question

When is onMounted appropriate?

Answer

onMounted runs after the component DOM is inserted, making it suitable for DOM-dependent or client-only setup.

Revision Notes

Key Takeaways

  • 1. onMounted fires after the component's DOM is inserted and is the place for subscriptions.
  • 2. onUpdated runs after each re-render caused by reactive state changes.
  • 3. onUnmounted fires after removal and is where listeners and timers should be released.

Interview Tips

  • • Explain Lifecycle Hooks with one concrete example from real vue work, not a textbook restatement.
  • • Discuss the trade-off: when Lifecycle Hooks helps and when a lighter approach wins.
  • • Place Lifecycle Hooks inside the Lifecycles and Composables phase — interviewers check that you see the progression, not isolated facts.

Cheat Sheet

Lifecycle Hooks Cheat Sheet

Phase: Lifecycles and Composables | Level: beginner

Key points:

  • onMounted fires after the component's DOM is inserted and is the place for subscriptions.
  • onUpdated runs after each re-render caused by reactive state changes.
  • onUnmounted fires after removal and is where listeners and timers should be released.
  • Setup code runs before mounting, so most synchronous work needs no hook at all.

Tags: vue, lifecycle, hooks

Continue Learning

Next Topics

Related Reading