Skip to the solution
MediumFrontend10 min read

What are Vue lifecycle hooks?

120 views

The problem

Question presented to candidate: "Walk me through the lifecycle of a Vue 3 component. When does each hook run, in what order do a parent and its child fire, and where would you put a data fetch, a DOM measurement and a cleanup?"

What a strong answer should cover:

  • The phases: setup (or beforeCreate/created), mount (onBeforeMount, onMounted), update (onBeforeUpdate, onUpdated) and unmount (onBeforeUnmount, onUnmounted).
  • Order between parent and child: parent setup and beforeMount, then the child completes its mount, then the parent's onMounted; unmount runs the parent's onBeforeUnmount first and its onUnmounted last.
  • In the Composition API, setup() replaces beforeCreate and created and runs before both.
  • Hooks must be registered synchronously during setup; a late registration logs a warning and never runs.
  • SSR runs only setup (and onServerPrefetch); mount, update and unmount hooks never run on the server.
  • The extra hooks: onActivated/onDeactivated (KeepAlive), onErrorCaptured, and the dev-only onRenderTracked/onRenderTriggered.

Clarifying questions expected:

  • "Composition API or Options API names? They map one to one, but the vocabulary differs."
  • "Does the app use SSR or KeepAlive? Both change which hooks run."

Code / implementation expected: Optional β€” a parent and child that log each hook, to prove the order rather than recite it.

  • lifecycle

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

10 min read Β· 11 sections

Read the code

VueParent and child hooks logged through mount, update and unmount
<script setup>
import {
  ref, h, defineComponent, onBeforeMount, onMounted, onBeforeUpdate,
  onUpdated, onBeforeUnmount, onUnmounted,
} from "vue";

// A child defined inline, so the whole demo is one file.
const Child = defineComponent({
  props: { n: Number },
  setup(props) {
    console.log("child  setup");
    onBeforeMount(() => console.log("child  onBeforeMount"));
    onMounted(() => console.log("child  onMounted"));
    onBeforeUpdate(() => console.log("child  onBeforeUpdate"));
    onUpdated(() => console.log("child  onUpdated"));
    onBeforeUnmount(() => console.log("child  onBeforeUnmount"));
    onUnmounted(() => console.log("child  onUnmounted"));
    return () => h("p", `child sees n = ${props.n}`);
  },
});

const n = ref(1);
const show = ref(true);
console.log("parent setup");
onBeforeMount(() => console.log("parent onBeforeMount"));
onMounted(() => console.log("parent onMounted"));
onBeforeUpdate(() => console.log("parent onBeforeUpdate"));
onUpdated(() => console.log("parent onUpdated"));
onBeforeUnmount(() => console.log("parent onBeforeUnmount"));
onUnmounted(() => console.log("parent onUnmounted"));
</script>

<template>
  <button id="inc" @click="n++">n++</button>
  <button id="toggle" @click="show = !show">toggle child</button>
  <Child v-if="show" :n="n" />
</template>
Vuesetup() versus beforeCreate/created, and onActivated/onDeactivated under KeepAlive
<script>
import { h, defineComponent, onMounted, KeepAlive, onActivated, onDeactivated, ref } from "vue";
const Kid = (name) => defineComponent({
  name,
  setup() {
    console.log(name, "setup");
    onMounted(() => console.log(name, "onMounted"));
    onActivated(() => console.log(name, "onActivated"));
    onDeactivated(() => console.log(name, "onDeactivated"));
    return () => h("span", name);
  },
});
const A = Kid("A"), B = Kid("B");
export default {
  components: { KeepAlive },
  setup() {
    console.log("root setup()");
    onMounted(() => console.log("root onMounted (from setup)"));
    const which = ref("A");
    return { which, A, B };
  },
  beforeCreate() { console.log("root beforeCreate"); },
  created() { console.log("root created, this.which =", this.which); },
  beforeMount() { console.log("root beforeMount"); },
  mounted() { console.log("root mounted (option)"); },
};
</script>
<template>
  <button id="sw" @click="which = which === 'A' ? 'B' : 'A'">switch</button>
  <KeepAlive><component :is="which === 'A' ? A : B" /></KeepAlive>
</template>

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 69 of 92 in Vue.js

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All Vue.js questions
Up nextMedium

Why is the :key attribute important in v-for?

Continue