Vue.js Lifecycle Hooks Explained Step by Step
Vue.js has a way of making frontend development feel elegant, almost calm. You build a component, wire up some data, add a template, and the framework takes care of a lot of the heavy lifting behind the scenes. But every Vue component has a life of its own. It is created, mounted to the page, updated when state changes, and eventually removed. Lifecycle hooks are the moments where your code can step in and say, “I know what’s happening here, and I need to do something at this exact stage.”
If you have ever wondered why a certain piece of code works only inside mounted, or why accessing the DOM too early gives you nothing useful, or why cleanup matters so much when components disappear, then lifecycle hooks are the key. They are not just a set of framework events. They are the rhythm of a Vue component.
In this article, we will walk through Vue.js lifecycle hooks step by step, from the first moment a component is born to the final moment it leaves the screen. We will explain the purpose of each hook, show practical code examples, compare Vue 2 and Vue 3, and connect the hooks to real-world use cases such as API requests, timers, event listeners, form handling, and DOM manipulation. By the end, lifecycle hooks should feel less like a memorization problem and more like a natural part of how you think about building components.
What lifecycle hooks really are
A Vue component does not simply appear on the page fully formed. It goes through phases. At each phase, Vue gives you a hook, which is a special function you can define to run at a specific time.
Think of it like building a small machine. First, the parts are prepared. Then the machine is assembled. Then it starts working. While it is working, data can change, the screen can update, and events can happen. Finally, the machine is turned off and cleaned up. Lifecycle hooks let you attach your own code to those transitions.
That is the whole idea: hooks are places where your logic can safely run when Vue reaches a particular stage.
For example:
If you need to initialize reactive data, a creation hook is useful.
If you need to read or manipulate the DOM, a mount hook is the right place.
If you need to react to changing props or state, update hooks help.
If you need to clean up timers, listeners, or subscriptions, unmount hooks matter a lot.
The biggest mistake beginners make is treating lifecycle hooks as random functions with mysterious names. They are not random. Each one corresponds to a very specific moment in a component’s lifetime.
Vue 2 and Vue 3 lifecycle: the big picture
The lifecycle in Vue 2 and Vue 3 is conceptually the same, but the syntax depends on whether you are using the Options API or Composition API.
In the Options API, lifecycle hooks are written as options in the component object:
export default {
data() {
return {
message: 'Hello Vue!'
}
},
created() {
console.log('Component created')
},
mounted() {
console.log('Component mounted')
}
}
In the Composition API, especially inside setup(), you use imported hook functions:
import { onMounted, onUnmounted } from 'vue'
export default {
setup() {
onMounted(() => {
console.log('Mounted')
})
onUnmounted(() => {
console.log('Unmounted')
})
}
}
The names may look different, but the meaning is the same. The component is still going through creation, mounting, updating, and destruction. The framework just gives you a different way to plug into those moments.
The full lifecycle flow
Before we zoom in on each hook, it helps to understand the overall flow. A component generally moves through these phases:
It is created.
Its reactive state is initialized.
It is mounted to the DOM.
It reacts to data changes and re-renders.
It is unmounted and cleaned up.
That sounds simple, but there are a lot of details inside those steps. For example, a component may be created before it has access to the DOM. It may have data ready before its template is inserted. It may re-render many times while staying alive on the page. It may also be kept alive with caching, which introduces additional hooks.
Once you understand this flow, the hooks become much easier to remember. Each one answers a practical question:
“Has my component been initialized yet?”
“Is the DOM available yet?”
“Did something change?”
“Is this component about to disappear?”
“Should I clean up something now?”
Let us go through the hooks one by one.
beforeCreate: the earliest moment
beforeCreate is one of the earliest hooks in Vue 2’s Options API. It runs before Vue has set up the component’s data, computed properties, methods, and watchers.
At this stage, the component exists, but it is not fully ready. You cannot rely on reactive data yet. That is why this hook is rarely used in everyday application code.
Here is a simple example:
export default {
beforeCreate() {
console.log('beforeCreate hook')
console.log(this.message) // usually undefined here
},
data() {
return {
message: 'Hello'
}
}
}
At beforeCreate, the component instance exists, but the reactive system has not fully wired everything together. That makes this hook useful only in rare situations, such as plugin-level logic or very specific initialization behavior.
In real projects, most developers barely touch beforeCreate. That is perfectly normal.
created: the component is alive, but not mounted
The created hook is much more useful. By the time created runs, Vue has set up reactive data, computed properties, methods, and watchers. You can access data, call methods, and work with the component’s internal state.
However, the DOM is still not mounted yet. That means you should not try to access actual rendered elements here.
A common use case for created is fetching data early, especially if the request does not depend on the DOM.
export default {
data() {
return {
users: [],
loading: false
}
},
created() {
this.loading = true
fetch('https://jsonplaceholder.typicode.com/users')
.then(response => response.json())
.then(data => {
this.users = data
})
.catch(error => {
console.error('Error fetching users:', error)
})
.finally(() => {
this.loading = false
})
}
}
This is a nice place to start loading data because the component state is available, even though the page is not yet painted.
A gentle rule of thumb: use created for logic that depends on reactive data, and use mounted for logic that depends on the rendered DOM.
beforeMount: just before the DOM is inserted
beforeMount runs after the component is ready but before Vue inserts it into the DOM. At this point, the component has the template and the virtual DOM structure prepared, but the real browser DOM has not yet been attached.
This hook is useful in edge cases, but it is not commonly needed for ordinary app code.
export default {
beforeMount() {
console.log('About to mount')
}
}
You usually do not choose beforeMount for practical business logic unless you have a very specific reason to run something right before rendering.
mounted: one of the most important hooks
mounted is probably the hook most developers use the most. It runs after the component has been inserted into the DOM. This means you can now safely access elements, measure sizes, initialize third-party libraries, focus inputs, or interact with browser APIs that require actual DOM nodes.
This is the place where many beginners first discover why lifecycle timing matters.
For example, imagine you want to focus an input automatically when a form loads:
<template>
<input ref="nameInput" type="text" placeholder="Enter your name" />
</template>
<script>
export default {
mounted() {
this.$refs.nameInput.focus()
}
}
</script>
This works because the input exists in the DOM by the time mounted runs.
Another practical example is integrating a chart library:
import Chart from 'chart.js/auto'
export default {
mounted() {
const canvas = this.$refs.chartCanvas
this.chart = new Chart(canvas, {
type: 'line',
data: {
labels: ['Jan', 'Feb', 'Mar'],
datasets: [
{
label: 'Sales',
data: [10, 20, 15]
}
]
}
})
}
}
If you try to initialize the chart too early, before the canvas exists, it will fail or behave unpredictably. mounted gives you the safe moment.
This hook is also a good place to register browser event listeners.
export default {
mounted() {
window.addEventListener('resize', this.handleResize)
},
methods: {
handleResize() {
console.log('Window resized')
}
}
}
But when you add listeners, you should also remove them later in beforeUnmount or unmounted, which we will cover soon.
beforeUpdate: just before Vue re-renders
beforeUpdate runs after reactive data changes but before Vue updates the DOM with the new render output. It is a good place to inspect the state right before the re-render happens.
This hook is less commonly used in regular development, but it can be useful if you need to compare pre-update and post-update conditions.
export default {
data() {
return {
count: 0
}
},
beforeUpdate() {
console.log('Count changed, DOM is about to update')
}
}
There is an important difference between state and DOM here. The data has already changed, but the browser still shows the old rendered version until Vue finishes the update cycle.
That timing detail can matter when you are building custom UI behaviors or debugging update flows.
updated: after the DOM has reacted to changes
updated runs after Vue has re-rendered the component and patched the DOM. The component’s visual output now reflects the new state.
This hook is useful when you need to do something after the view has changed, such as reading the updated layout or responding to DOM changes.
export default {
data() {
return {
message: 'Hello'
}
},
updated() {
console.log('Component updated in the DOM')
}
}
A subtle warning is worth mentioning here: avoid changing reactive data again inside updated unless you are very careful. Doing so can lead to update loops. That is one reason why this hook is not a place for casual state mutations.
A more practical use is when you need to interact with something that depends on the new DOM layout, such as scrolling to a newly rendered item:
export default {
updated() {
const element = this.$refs.latestMessage
if (element) {
element.scrollIntoView({ behavior: 'smooth' })
}
}
}
That said, often there is a cleaner alternative, such as using nextTick() after a specific state change.
beforeUnmount: prepare to leave
In Vue 3, beforeUnmount is the hook that runs just before the component is removed from the DOM. In Vue 2, the equivalent is beforeDestroy.
This is a critical moment for cleanup. If your component created timers, event listeners, subscriptions, or external resources, this is where you should shut them down.
For example, if your component adds a resize listener on window, remove it here:
export default {
mounted() {
window.addEventListener('resize', this.handleResize)
},
beforeUnmount() {
window.removeEventListener('resize', this.handleResize)
},
methods: {
handleResize() {
console.log('Resized')
}
}
}
This kind of cleanup is easy to forget, especially in small components, but the habit matters. A tiny memory leak may not hurt once, but many small leaks can become a real problem in a larger application.
unmounted: the final goodbye
unmounted runs after the component has been removed from the DOM. At this point, the component is no longer visible and is no longer part of the active interface.
This hook is still a useful place for cleanup or logging, especially if you want to know that the component lifecycle has fully ended.
export default {
unmounted() {
console.log('Component removed from DOM')
}
}
In practice, many cleanup actions are placed in beforeUnmount, because you often want to remove listeners or cancel timers before the element disappears entirely. But unmounted is still part of the lifecycle story, and it can be helpful for tracing behavior.
Vue 2 equivalents: beforeDestroy and destroyed
If you are working with Vue 2, the lifecycle names are slightly different in the teardown phase:
beforeDestroyinstead ofbeforeUnmountdestroyedinstead ofunmounted
The concept remains the same. The component is getting removed, and you should clean up any resources.
Here is a Vue 2 example:
export default {
mounted() {
window.addEventListener('scroll', this.handleScroll)
},
beforeDestroy() {
window.removeEventListener('scroll', this.handleScroll)
},
methods: {
handleScroll() {
console.log('Scrolling...')
}
}
}
If you are learning Vue now, you will likely work mostly with Vue 3, but many older codebases still use Vue 2, so it helps to know the naming difference.
Lifecycle hooks in the Composition API
With Vue 3, the Composition API changed the way many developers organize logic. Instead of lifecycle hooks living in the component object, they are imported and called inside setup().
Here is the basic shape:
<script setup>
import { onMounted, onUpdated, onUnmounted } from 'vue'
onMounted(() => {
console.log('Mounted')
})
onUpdated(() => {
console.log('Updated')
})
onUnmounted(() => {
console.log('Unmounted')
})
</script>
This style is very clean and flexible. It allows you to group logic by feature instead of by option category. For example, you can write a composable function that sets up listeners and includes its own lifecycle cleanup.
Example:
import { onMounted, onUnmounted } from 'vue'
export function useWindowWidth() {
const width = ref(window.innerWidth)
const updateWidth = () => {
width.value = window.innerWidth
}
onMounted(() => {
window.addEventListener('resize', updateWidth)
})
onUnmounted(() => {
window.removeEventListener('resize', updateWidth)
})
return { width }
}
This kind of pattern is one of the nicest things about Vue 3. Lifecycle behavior can live close to the logic that needs it, rather than being spread across a large component object.
Step-by-step example: a complete lifecycle walkthrough
Let us build a small component and watch its lifecycle in a practical way. Imagine a dashboard widget that loads user data, starts a timer, and listens for window resize events.
Vue 3 Options API example
<template>
<section>
<h2>User Dashboard</h2>
<p v-if="loading">Loading users...</p>
<ul v-else>
<li v-for="user in users" :key="user.id">{{ user.name }}</li>
</ul>
<p>Time active: {{ seconds }} seconds</p>
</section>
</template>
<script>
export default {
data() {
return {
users: [],
loading: true,
seconds: 0,
timer: null
}
},
created() {
console.log('created: data is ready')
fetch('https://jsonplaceholder.typicode.com/users')
.then(res => res.json())
.then(data => {
this.users = data
this.loading = false
})
},
mounted() {
console.log('mounted: DOM is available')
window.addEventListener('resize', this.handleResize)
this.timer = setInterval(() => {
this.seconds++
}, 1000)
},
beforeUnmount() {
console.log('beforeUnmount: cleaning up')
window.removeEventListener('resize', this.handleResize)
clearInterval(this.timer)
},
unmounted() {
console.log('unmounted: component removed')
},
methods: {
handleResize() {
console.log('Window width:', window.innerWidth)
}
}
}
</script>
Now let us walk through what happens.
First, Vue creates the component instance and prepares reactivity. The created hook runs, so the API request begins early. Then the template gets rendered and mounted to the page. At that moment, mounted runs, so the component can attach the window listener and start the timer. Later, when the component is removed from the page, beforeUnmount clears the interval and removes the event listener. Finally, unmounted confirms that the component is gone.
That whole flow is not just academic. It is exactly how you keep components healthy in real applications.
Why mounted is not the right place for everything
New Vue developers often try to place all their code in mounted, and at first that seems fine. The page loads, the DOM exists, and the code works. But over time, this habit can make components harder to understand and maintain.
For example, fetching data that does not need the DOM can often happen earlier in created. If you move that request to mounted, the user may wait a little longer for the request to start, even though there was no reason to delay it. On the other hand, if your code depends on actual DOM elements, created is too early.
The important lesson is to match the hook to the need:
Use
createdfor reactive state and early data fetching.Use
mountedfor DOM access and browser APIs.Use
beforeUnmountfor cleanup.Avoid forcing everything into one hook.
That distinction leads to cleaner code and fewer timing bugs.
Accessing the DOM with refs
One of the most common reasons to use lifecycle hooks is to access DOM elements through refs. The trick is that refs are not available until the component has mounted.
Here is a simple example:
<template>
<div>
<input ref="emailInput" type="email" placeholder="Enter email" />
<button @click="focusInput">Focus Input</button>
</div>
</template>
<script>
export default {
mounted() {
this.$refs.emailInput.focus()
},
methods: {
focusInput() {
this.$refs.emailInput.focus()
}
}
}
</script>
If you attempted to focus that input in created, it would not work because the DOM element does not exist yet. That is one of the clearest examples of why hook timing matters.
Using nextTick with lifecycle timing
Sometimes the DOM has technically updated, but the browser has not finished reflecting the change in a way you can measure immediately. That is where nextTick() comes in.
Vue batches updates for efficiency. When state changes, Vue often waits until the current call stack finishes before applying the DOM update. If you need to do something right after the DOM reflects a state change, nextTick() is helpful.
Example:
<template>
<div>
<button @click="addItem">Add item</button>
<ul ref="list">
<li v-for="item in items" :key="item">{{ item }}</li>
</ul>
</div>
</template>
<script>
import { nextTick } from 'vue'
export default {
data() {
return {
items: ['A', 'B', 'C']
}
},
methods: {
async addItem() {
this.items.push('D')
await nextTick()
this.$refs.list.lastElementChild.scrollIntoView({ behavior: 'smooth' })
}
}
}
</script>
This is often cleaner than trying to force logic into updated, because it ties the post-update action directly to the state change that caused it.
Watchers versus lifecycle hooks
Beginners sometimes confuse watchers with lifecycle hooks. They are related, but they are not the same thing.
A lifecycle hook runs at a framework-defined moment in the component’s existence. A watcher runs when a specific reactive value changes.
Lifecycle hooks are about phases. Watchers are about changes.
For example:
export default {
data() {
return {
searchTerm: ''
}
},
watch: {
searchTerm(newValue) {
console.log('Search term changed to:', newValue)
}
}
}
That watcher only reacts to searchTerm changes. It does not care whether the component is being created or destroyed. Meanwhile, lifecycle hooks care about the entire journey of the component.
That difference matters because the same app may need both. You might use mounted to start listening for events and a watcher to react to a specific input value.
Common real-world patterns
Lifecycle hooks become much more useful when connected to actual tasks. Here are some of the patterns developers use every day.
Fetching data when the component loads
A common pattern is to fetch data in created or mounted.
Use created when the request does not need the DOM.
created() {
this.fetchPosts()
}
Use mounted when the request depends on DOM state or third-party UI setup.
mounted() {
this.initializeSlider()
}
Starting and stopping timers
Timers should almost always be cleaned up.
mounted() {
this.intervalId = setInterval(() => {
this.now = new Date()
}, 1000)
},
beforeUnmount() {
clearInterval(this.intervalId)
}
Managing global listeners
Always remove them.
mounted() {
window.addEventListener('keydown', this.handleKeydown)
},
beforeUnmount() {
window.removeEventListener('keydown', this.handleKeydown)
}
Integrating third-party libraries
Libraries that touch the DOM usually belong in mounted.
mounted() {
this.editor = new SomeRichTextEditor(this.$refs.editor)
}
If the library has its own destroy method, call it during cleanup.
beforeUnmount() {
this.editor.destroy()
}
Working with focus and scroll behavior
Anything involving focus, measurement, or scrolling usually needs the DOM to be mounted.
mounted() {
this.$refs.searchInput.focus()
}
A deeper look at the Composition API hooks
The Composition API uses hook functions instead of component options. Here is a quick map:
onBeforeMountonMountedonBeforeUpdateonUpdatedonBeforeUnmountonUnmounted
These are the same lifecycle moments, just expressed differently.
A full Composition API example:
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'
const count = ref(0)
let timer = null
function handleResize() {
console.log('Resized to:', window.innerWidth)
}
onMounted(() => {
window.addEventListener('resize', handleResize)
timer = setInterval(() => {
count.value++
}, 1000)
})
onBeforeUnmount(() => {
window.removeEventListener('resize', handleResize)
clearInterval(timer)
})
</script>
<template>
<div>
<p>Count: {{ count }}</p>
</div>
</template>
This style is concise, but it is still very readable once you get used to it. The key advantage is that related logic can stay together. If a composable adds a listener, the cleanup can live right beside it.
KeepAlive hooks: activated and deactivated
Vue also has special hooks for components wrapped in <KeepAlive>. These are useful when a component is cached instead of fully destroyed.
The hooks are:
activateddeactivated
They let you know when a cached component becomes active or inactive.
Example:
<script>
export default {
activated() {
console.log('Component activated again')
},
deactivated() {
console.log('Component cached but inactive')
}
}
</script>
This matters in tab interfaces, route caching, or dashboards where you want to preserve component state instead of recreating it every time.
Error handling with lifecycle awareness
Lifecycle hooks are also useful when dealing with uncertainty. A component may mount successfully, but an API request may fail, or a third-party library may not initialize correctly.
The hook itself is not an error handler, but it is often the place where setup happens, so you should code defensively.
Example:
mounted() {
try {
this.startWidget()
} catch (error) {
console.error('Widget failed to start:', error)
}
}
And for data loading:
created() {
fetch('/api/data')
.then(res => res.json())
.then(data => {
this.items = data
})
.catch(error => {
this.error = 'Failed to load data'
console.error(error)
})
}
A careful developer does not just ask, “Which hook should I use?” They also ask, “What happens if this step fails?” That mindset makes components much more reliable.
A practical mental model for remembering the hooks
Here is a simple way to remember the lifecycle:
First, the component is prepared. That is creation time. Then it is shown. That is mount time. Then it changes while the user interacts with it. That is update time. Finally, it is removed. That is unmount time.
You can reduce the whole thing to four questions:
Is the component ready?
Is the DOM available?
Is the view changing?
Is the component leaving?
When you can answer those questions, choosing the correct hook becomes much easier.
Mistakes developers make with lifecycle hooks
A few mistakes appear again and again.
The first is trying to access the DOM too early. If the element does not exist yet, the code cannot work. That is why mounted matters.
The second is forgetting cleanup. Timers, listeners, and subscriptions do not disappear automatically just because your component does. If you leave them running, they can create memory leaks or unexpected behavior.
The third is putting update logic inside updated when a watcher or direct post-change action would be clearer. updated is powerful, but it is not always the best tool.
The fourth is treating lifecycle hooks as a place to dump unrelated code. A component becomes easier to maintain when each hook has a clear purpose.
The fifth is ignoring Vue 2 versus Vue 3 naming differences. If you work in a legacy codebase, beforeDestroy and destroyed are still common. Knowing the equivalent names saves confusion.
Building a small real-world component from scratch
Let us put the ideas together in one simple component that loads data, shows a timer, and cleans up correctly.
<template>
<div class="profile-card">
<h2>User Profile</h2>
<p v-if="loading">Loading profile...</p>
<p v-else-if="error">{{ error }}</p>
<div v-else>
<p><strong>Name:</strong> {{ user.name }}</p>
<p><strong>Email:</strong> {{ user.email }}</p>
<p><strong>Seconds on page:</strong> {{ seconds }}</p>
</div>
<button @click="refreshUser">Refresh</button>
</div>
</template>
<script>
export default {
data() {
return {
user: {},
loading: true,
error: '',
seconds: 0,
timerId: null
}
},
created() {
this.loadUser()
},
mounted() {
this.timerId = setInterval(() => {
this.seconds++
}, 1000)
},
beforeUnmount() {
clearInterval(this.timerId)
},
methods: {
async loadUser() {
this.loading = true
this.error = ''
try {
const response = await fetch('https://jsonplaceholder.typicode.com/users/1')
if (!response.ok) {
throw new Error('Network response was not ok')
}
this.user = await response.json()
} catch (err) {
this.error = 'Could not load user data.'
console.error(err)
} finally {
this.loading = false
}
},
refreshUser() {
this.loadUser()
}
}
}
</script>
This component does several things well. It starts loading data early in created. It starts a timer only after the component is on screen. It clears the timer before unmounting. It also handles loading and error states so the UI remains friendly.
That is lifecycle thinking in practice. The code is not just “working.” It is working in the right place, at the right time.
Lifecycle hooks and user experience
Hooks are not just for developers. They influence the user experience directly.
If you fetch data earlier, the page may feel faster. If you focus the right input at the right time, the interface feels thoughtful. If you clean up listeners correctly, the app behaves smoothly and predictably. If you accidentally attach duplicate listeners, the app may feel broken even though the code “looks fine.”
Good lifecycle usage leads to software that feels polished. Users may never know why the experience is better, but they will feel it.
Lifecycle hooks in reusable composables
One of the strongest patterns in Vue 3 is building reusable composables that manage their own lifecycle behavior.
For example, a composable for tracking mouse position:
import { ref, onMounted, onUnmounted } from 'vue'
export function useMousePosition() {
const x = ref(0)
const y = ref(0)
function updatePosition(event) {
x.value = event.clientX
y.value = event.clientY
}
onMounted(() => {
window.addEventListener('mousemove', updatePosition)
})
onUnmounted(() => {
window.removeEventListener('mousemove', updatePosition)
})
return { x, y }
}
Then in a component:
<script setup>
import { useMousePosition } from './useMousePosition'
const { x, y } = useMousePosition()
</script>
<template>
<p>Mouse: {{ x }}, {{ y }}</p>
</template>
This is a beautiful example of lifecycle logic becoming reusable. The component does not need to know the details. It simply uses the composable and benefits from the cleanup automatically.
When not to use lifecycle hooks
Not every task belongs in a lifecycle hook. Sometimes a normal method is enough. Sometimes a watcher is a better fit. Sometimes a computed property is the right answer.
Use a lifecycle hook when the timing matters. Use a method when the action is user-driven. Use a watcher when a reactive value must be observed. Use computed properties when you are deriving values from state.
That distinction keeps your code clear. Hooks are powerful, but they should not become a catch-all for every piece of behavior.
Final thoughts
Vue’s lifecycle hooks are one of the features that make the framework feel structured without feeling rigid. They give you control at exactly the moments when control matters most. Create data early, mount DOM-sensitive logic at the right time, update carefully, and clean up properly when the component leaves the page. That is the whole rhythm.
Once you understand the lifecycle, Vue development becomes much more intuitive. You stop guessing where code should go. You start placing code where it naturally belongs. That shift is small at first, but it changes how you build components in a meaningful way.
The best developers do not just know the hook names. They understand the reason behind each one. And once that reason clicks, lifecycle hooks stop being a list to memorize and start becoming a tool you can trust.
If you are learning Vue, spend time building small components and placing logic in different hooks on purpose. Notice what works, what fails, and why. That hands-on exploration is often the fastest way to make the lifecycle feel real.
Vue does not just render components. It gives them a life cycle. And once you can read that cycle clearly, you can write better, cleaner, more reliable frontend code.
Quick reference of the main hooks
beforeCreate runs before data and methods are initialized.created runs after reactivity is ready but before the DOM exists.beforeMount runs just before the component is inserted into the DOM.mounted runs after the component is mounted and the DOM is available.beforeUpdate runs before reactive changes are reflected in the DOM.updated runs after the DOM has been updated.beforeUnmount runs just before removal and is ideal for cleanup.unmounted runs after removal from the DOM.activated and deactivated are used with cached components inside KeepAlive.