Component Lifecycle Hooks
Challenge
Lifecycle Hooks are a very commonly used feature in Vue components, and some of them have been renamed in Vue 3:
beforeDestroy
->beforeUnmount
destroyed
->unmounted
So whenever you need to use these lifecycle hooks in your cross-compatible components, you have to make sure that your hooks are run when used with either version. As an example, in the following example, created
would run in both versions, but with Vue 3, the beforeDestroy
hook would never be called (though you would get a console warning in development):
export default {
created() {
window.addEventListener('resize', this.handler)
},
beforeDestroy() {
window.removeEventListener('resize', this.handler)
}
methods: {
handler() { /*... */ }
}
}
Solution
This breaking change can be handled manually or with the help of @vue-bridge/runtime
.
Manual handling
export default {
created() {
window.addEventListener('resize', this.handler)
},
beforeDestroy() {
this.removeListener()
},
beforeUnmount() {
this.removeListener()
}
methods: {
removeListener() {
window.removeEventListener('resize', this.handler)
}
handler() { /*... */ }
}
}
While this works, this has a couple of obvious drawbacks:
- You need to remember to do that!
- You end up with unnecessary code for either Version in your components.
Automatic handling with @vue-bridge/runtime
(Options API)
When using defineComponent()
from @vue-bridge/runtime
, you can just use Vue 3 lifecycle names and forget about it. A runtime, the component lifecycles will be renamed to the ones expected by the Vue version that the component runs in.
import { defineComponent } from '@vue-bridge/runtime'
export default defineComponent({
created() {
window.addEventListener('resize', this.handler)
},
beforeUnmount() {
window.removeEventListener('resize', this.handler)
}
methods: {
handler() { /*... */ }
}
})
Automatic handling with @vue-demi
(Composition-API)
Vue 2.7
supports composition API, and in composition API, the old lifecycle names are already gone. So you can simply use the new ones from Vue 3:
import { defineComponent, onBeforeUnmount } from 'vue'
export default defineComponent({
setup() {
function handler() { /*... */ }
window.addEventListener('resize', this.handler)
onBeforeUnmount(() => {
window.removeEventListener('resize', this.handler)
})
},
})