Vue.js lifecycle hooks - vue.js

I was sure that the lifecycle hooks in Vue were 8 (beforeCreate, created, beforeMount, mounted, beforeUpdate, updated, beforeDestroy, destroyed) but today I found out(https://v2.vuejs.org/v2/api/#activated) that there are 3 more:
• activated
• deactivated
• error captured
Somebody can explain how these 3 work? Is possible to test them with a console.log? (Just to understand when they are called)

First, a little context:
In Vue 2.0+, there is a built-in component called <keep-alive> that takes the child element inside it and keeps it alive in memory as a cached component. Normally, Vue would reuse a component if its props change, but maybe the component is very complex and is slow to update. You could wrap it with <keep-alive> and the component would be cached for the props provided to it.
When a component inside a <keep-alive> is updated, the activated life-cycle hook is called. When that component is cached and set aside, the deactivated life-cycle hook is called.
The errorCaptured life-cycle hook was added in Vue 2.5.0 and is called whenever an error is captured by a descendent component. So, if you have a component called A that has a child component called B, and that has a child component called C, then if C captures and error, the errorCaptured life-cycle hook will be called on both A and B.
These hooks all work the same as any other hook, so use them the same way.
export default {
data() {
return {}
},
mounted() {
console.log('mounted hook called')
},
errorCaptured(err, vm, info) {
console.log('error captured in component', vm)
console.error(err)
console.log('error info:', info)
},
activated() {
console.log('cached component is being used again')
},
deactivated() {
console.log('component is being kept alive in cache for now')
}
}
https://v2.vuejs.org/v2/api/#activated
https://v2.vuejs.org/v2/api/#deactivated
https://v2.vuejs.org/v2/api/#errorCaptured

I know it's already late for this answer but someone might also looking answer for
the problem. Vue.js disable's console.log function by default, so we have to enable it.
Just put "rules": { "no-console": "off",} on package.json
Cheers

Related

Does Vue automatically remove all vue/vuex watchers on component destroy?

If the component subscribes to the Vuex events like:
this.$store.watch or this.$store.subscribe
Is it necessary to remove the watcher during component destroy or Vue already takes care of it under the hood?
P.S: Current logic runs on 2.6.10 Vue version.
Following #Cristiano Soleti I checked if listeners are still being called after component that registered them was destroyed.
...and at least in 2.6.10 version, Vuex watcher are actually not removed automatically when component is destroyed. And thus should be unregistered explicitly by developer in beforeDestroy lifecycle hook.
The VueX docs are vague, however it does say "To stop watching, call the returned unwatch function." with no other information, which implies that watchers never get removed any other way: https://vuex.vuejs.org/api/#watch
So, you should manually remove a VueX watcher when destroying a component.
Here's an example:
MyComponent.vue
data: function() {
return {
myWatcher: null // Holds the watcher, so we can reference it
}
},
mounted() {
// Invoke the watcher
this.myWatcher = this.$store.watch(state => state.myStoreVariable, (valueNew, valueOld) => {
// Do stuff
console.log("valueOld: " + valueOld + ", valueNew: " + valueNew)
})
},
beforeDestroy () {
this.myWatcher() // Simply calling the watch holder as a function (ie with parentheses) will remove the watcher.
},

beforeDestroy hook for nuxt page component

I need to emit some events before leaving a particular page. So I'm thinking of using the beforeDestroy hook to do this. But it seems not triggering the method.
// pages/view.vue
beforeDestroy() {
this.$alertEvent('finished')
}
I'm also using the keep-alive directive on the <nuxt>
How can I trigger this method effectively?
for Nuxt 3 you can use onBeforeUnmount
onBeforeUnmount(() => {
alert('the component is destroyed')
})
https://vuejs.org/api/composition-api-lifecycle.html#onbeforeunmount
i think this should work .
maybe you have problem with this.$alertEvent('finished') so you cannot see the result
beforeDestroy() {
alert('the component is destroy')
},
If your component wrapped inside - this is what Nuxt keep-alive directive does, then your component will not be destroyed.
You should use deactivated hook.
https://v2.vuejs.org/v2/api/#deactivated

Detect exiting route changes in Vue

I'm working on a component which enables the user to undo the deletion of an item. However, the item should be deleted when the user navigates to another route. To achieve this I'm watching the route like so:
`watch: {
$route(to, from) {
if (this.showUndo === true) {
console.log('item will be deleted');
this.confirmDelete();
}
},
},
`
Unfortunately, this gets only triggered when I enter this specific route and not on exiting it. An explanation why that is or an alternative to my watch: - method would be much appreciated!
Basically I'm looking for an alternative to beforeRouteLeave since this is a sub-component and therefore I can't use Navigation Guards. Thanks!
Vue lifecycle hook- BeforeDestroy is fired right before teardown. Your component will still be fully present and functional. If you need to cleanup events or reactive subscriptions,
beforeDestroy would probably be the time to do it.
<script>
export default {
beforeDestroy() {
//Try like this
this.confirmDelete();
console.log('item will be deleted');
}
}
</script>
Ref - https://v2.vuejs.org/v2/api/#beforeDestroy

vue 2 lifecycle - how to stop beforeDestroy?

Can I add something to beforeDestroy to prevent destroying the component? ?
Or is there any way to prevent destroying the component ?
my case is that when I change spa page by vue-route, I use watch route first, but I found that doesn't trigger because the component just destroy..
As belmin bedak commented you can use keep-alive
when you use keep-alive two more lifecycle hooks come into action, they are activated and deactivated hooks instead of destroyed
The purpose of keep-alive is to cache and to not destroy the component
you can use include and exclude atteibutes of the keep-alive element and mention the names of the components that shoulb be included to be cached and be excluded from caching. Here is documentation
in case you want to forecefully destroy the component even if its cached you can use vm.$destroy() here
Further you can console.log in all the lifecycle hooks and check which lifecycle hook is being called
You can use vue-route navigation-guards, so if you call next(false) inside the hook, navigation will be aborted.
router.afterEach((to, from) => {
if(your condition){
next(false) //this will abort route navigation
}
})
According to this source: https://router.vuejs.org/guide/advanced/navigation-guards.html
I suggest you to do something like this with your Vue router:
const router = new VueRouter({ }); // declare your router with params
router.beforeEach((to, from, next) => {
if(yourCondition){
next(false); // prevent user from navigating somewhere
} else {
return next(); // navigate to next "page" as usual
}
});
This will prevent destroying your Vue instance on your declared condition, and it will also prevent user from navigating to another page.
Although I would consider #Vamsi Krishna "keep-alive" answer to be the proper "VueJS way" to solve this issue, I was not willing to refactor part of my code for it.
I also couldn't use the Vue router navigation guard "as-is" because in the case of beforeRouterLeave, even though using next(false) prevented the route from continuing, the component in Vue was ALREADY destroyed. Any state I had that wasn't saved would be lost, which defeats the purpose of cancelling the route change.
This wasn't what I wanted, as I needed the state of the form/settings in the component to remain (the component reloaded itself and kept the same route).
So I came up with a strategy that still used a navigation guard, but also cached any form changes/settings I had in the component in-memory, eg. I add a beforeRouteLeave hook in the component:
beforeRouteLeave (to, from, next) {
if (!this.isFormDirty() || confirm('Discard changes made?')) {
_cachedComponentData = null // delete the cached data
next()
} else {
_cachedComponentData = this.componentData // store the cached data based on component data you are setting during use of the component
next(false)
}
}
Outside the Vue component, I initialize _cachedComponentData
<script>
let _cachedComponentData = null
module.exports = {
...component code here
}
<script>
Then in the created or mounted life cycle hooks, I can set the _cachedComponentData to "continue where the user left off" in the component:
...
if (_cachedComponentData) {
this.componentData = _cachedComponentData
}
...

Precedence in lifecycle hooks with Vue.js and Vue-router

I'm building an app with vue and vue-router. In some routes, I need to check some conditions first, if those conditions are not satisfied, then redirect to another component, so I used the activate hook on the router option of my component, and it works fine. Also, inside that same component, I have the vue created hook to load some data, the thing is that if those conditions that I mentioned before are not met, then I can't load the data in the created hook. What I would expect is that if that condition is not met, and the redirect hook was called, then the created hook wont get triggered, but what is actually happening is that whene that condition is false, then the redirect of the activate hook get calledn and also the created hook from Vue. So, more than a solution for my particular use case, I would like to know the order of execution of the hooks when using vue and vue router together.
For Vue 2.0:
beforeCreate
created
beforeMount
mounted
beforeUpdate
updated
beforeDestroy
destroyed
Now when using vue-router 2.0, the data fetching can be done at two places, as per their doc:
Fetching After Navigation: perform the navigation first, and fetch
data in the incoming component's lifecycle hook. Display a loading
state while data is being fetched.
Fetching Before Navigation: Fetch data before navigation in the route
enter guard, and perform the navigation after data has been fetched.
For your case, you can write you data fetching logic in a function and call it inside the "created" hook of the component lifecylce. If at all the data changes with the route, then write a watcher on the $route object, which will trigger your data fetching function.
As the data hook of vue-router 0.7 is deprecated and instead the $route object has been made reactive. Read more here.
Maybe you are interested in In-Component Guards (additional hooks available in components loaded using Vue Router)
const Foo = {
template: `...`,
beforeRouteEnter (to, from, next) {
// called before the route that renders this component is confirmed.
// does NOT have access to `this` component instance,
// because it has not been created yet when this guard is called!
},
beforeRouteUpdate (to, from, next) {
// called when the route that renders this component has changed,
// but this component is reused in the new route.
// For example, for a route with dynamic params `/foo/:id`, when we
// navigate between `/foo/1` and `/foo/2`, the same `Foo` component instance
// will be reused, and this hook will be called when that happens.
// has access to `this` component instance.
},
beforeRouteLeave (to, from, next) {
// called when the route that renders this component is about to
// be navigated away from.
// has access to `this` component instance.
}
}
https://router.vuejs.org/guide/advanced/navigation-guards.html#in-component-guards
If you use Vue + Vue Router and you are at RouteA and navigates from it to RouteB and each route/component register for something (e.g. receiving data supported by root) on "created" and unregister on "beforeDestroy" but when you leave RouteA its "beforeDestroy" is called after RouteB "created" so you have nothing registered! I have tested it and VUE 1 had correct order. It must be changed somewhere in VUE 2 + VUE Router 2.
Correct/expected hooks order in VUE 1 when going from RouteA to RouteB:
RouteA beforeDestroy
RouteB created
Incorrect/unexpected hooks order in VUE 2 when going from RouteA to RouteB:
RouteB created
RouteA beforeDestroy
Solution is to use "created" + "beforeRouteLeave" for VUE 2 + VUE Router 2.
Why not add console logs to each and see for yourself?
As far as I can tell without testing:
canReuse
canActivate
-- now the component instance is being created:
created
beforeCompile
compiled
-- (not sure wheither ready or activate comes first, but i guess ready)
ready
activate
data
For your particular case, the data fetching should happen in the data hook - that's what it's for, after all.