What's the Vue lifecycle chronology between components? - vue.js

Let's say I have a <router-view> showing one component (A) and through a <router-link> this component will be replaced by another one (B).
Both components have their own beforeCreate and beforeDestroy hooks. I'd expect that if I navigated from A to B the sequence of events would be:
A.beforeDestroy
B.beforeCreate
But after doing some tests it appears to be the exact opposite: B.beforeCreate is always called before A.beforeDestroy.
Is that correct? And if it's correct, why is it this way? Doesn't make sense to me...
In my case all those hooks interact with some common data, so I'm facing race conditions here... Any suggestion on how to deal with that? I need to get some things done before creating B that cannot be started before destroying A...

Before the previous component is destroyed, the next component will be created first.
The purpose is obviously to avoid flickering as the view transitions from the previous component to the next component.
If the behavior you wanted is to make sure that a code should be executed always after the beforeDestroy and not before, you should use the mounted or beforeMount lifecycle hook.

Related

can not get element by getElementById in beforeDestroy lifecycle vue

I use document.getElementById in beforeDestroy lifecycle to get an element. But getElementById returns null. If I use ref, I can get the element. Is there any difference between them? Why document.getElementById can't get the element?
There is an issue with the timing and there could be many reasons for that.
But in your case , The ref was still in the virtual DOM object, which will be destroyed within the destroy event (Unlike the document template).
That would be one reason Vue recommends to use $refs if possible.
I had the same problem. I thought the beforeDestroy hook was the right place to kill event listeners before leaving the component. For my surprise, when the route changes, the component is already unmounted when this hook is called.
This is vue.js version 2, I don’t know if it is better in version 3.

keep-alive doesn't cache component

I have issue with having keep-alive actually keeping components alive.
Component that is being rendered in router-view have async fetching after component is mounted. My issue is that after the first time component shows up, when I render other component in that very same router, and then go back, then first component rerender as normal instead of keeping fetched data as it was.
I checked hooks and besides activated and deactivated also created hook fires which I suppose shouldn't be the case beyond first render. Also when I switch components destroyed hook fires which also shouldn't happen.
.container-fluid
.row.wrapper
aside.col-12.col-sm-2.p-0
nav.navbar.navbar-light.navbar-expand-sm.align-items-start.flex-sm-column.flex-row.text-uppercase#navbar1
a.navbar-toggler(href='', data-toggle='collapse', data-target='.sidebar')
span.navbar-toggler-icon
.collapse.navbar-collapse.sidebar
ul.flex-column.navbar-nav.w-100.justify-content-between
li.nav-item
router-link.nav-link.pl-0(to='candidates' data-toggle="collapse" data-target=".navbar-collapse.show")
font-awesome-icon.fa-fw.mr-2(:icon="iconTachometer")
| Dashboard
main.col.bg-faded.py-3
.card
.card-body
keep-alive
router-view(:key="$route.fullPath")
Okay, I found the answer - and my apologies because turned out my question wasn't fully informed.
First thing - the component in question was already nested within another router-view so what I was actually doing was nesting one in another.
Therefore, to keep alive that nested/child router-view parent router-view also has to be wrapped with keep-alive.
Based on answer here: https://forum.vuejs.org/t/how-to-use-keep-alive-with-nested-router-component/46813/4
See Special Attributes - key:
It can also be used to force replacement of an element/component
instead of reusing it. This can be useful when you want to:
Properly trigger lifecycle hooks of a component;
Trigger transitions.
If you bind key to $route.fullPath, it will always force a replacement of the <router-view> element / component every time a navigation event occurs. So just remove :key.

Vue Single page app Router, what happens with the components when we change route?

Let's suppose I have a component called FirstPage, which is my default route, now FirstPage triggers an asynchronous call, with the help of an action of the vuex store, to be made each minute to a backend Api (it's triggered when the component is loaded as a route), now let's say I go to an about route that goes to an About component, is FirstPage still making the calls?
Edit:
I'm not developing an app with that yet, so I can't provide examples.
It's on my interest to know the behavior in these cases of the router, because whenever I change the route I would want to stop making the constant calls (as they won't be necessary).
The reason is that Depending on this I'd have to switch tooling for a project I have in mind.
In general, a component's instance will be destroyed when you navigate away from it. However, there are two exceptions to this ..
When you use routes with params. From the Vue Router docs
One thing to note when using routes with params is that when the user navigates from /user/foo to /user/bar, the same component instance will be reused. Since both routes render the same component, this is more efficient than destroying the old instance and then creating a new one. However, this also means that the lifecycle hooks of the component will not be called.
When you wrap your router-view component within a keep-alive element. Since the <router-view> is essentially a dynamic component.
Generally Vue does a very good job of housekeeping and cleaning up after a component's instance when it gets destroyed. But sometimes you'll have to do some manual cleanup, especially if you use some kind of external library. This is usually handled in the beforeDestroy hook of an instance's lifecycle.
In normal conditions, any logic/scripts/etc done at creation inside said component will be "purged" on the on destroy/close hooks (not only pertinent to vue but seen in lots of other tools), if there is a need to persist something then it should be in a higher scope (or other solution)
Any script written for the respective component only runs if the component is rendered in page. Once you go to about component replacing the previous component then previous script wont run.
you can make a parent component with a router-view and load in your page you always want to get loaded, so your FirstPage component, but this component should just have logic behind it, and no html because otherwise you will always see that rendered. Router-view the page you want to display the real html and stuff. I hope you get the idea, if not i could make an example for you. Goodluck.

is there A Communication Manager for vue components?

I was Vue.js now for a project and created and used a lot of components.
Now I started to have the problem of having too many eventemitters and props that I need to keep track of.
I guess to illustrate the problem the best I will use an example:
Lets say you have a main.vue and 2 or 3 Components.
One contains a button that should manipulate the other 2 components or switch them out.
Now I need to emit an event to the main.vue and then main.vue has to change a binded variable and pass props down to the other 2 components.
Alright: Now lets put the button in a component of of a component. You need to make sure that every link between a parent and a child is correct.
Now create a bit project and put a button in another components and you have to change everything.
So is there a good way to avoid this?
Something like a broadcast function so that every component is receiving the event?
Or a Manager that is handling the communication of all components?
use a flux pattern (vuex)
At first you may think that this does not really answer the question, since it deals with storage of data, and not handling of events. The flux pattern changes the architecture of your application by creating a single store (think database) that all components can read and write from. Coupled with the reactive nature of the reactive frameworks such as vue (or react), the components will react to a change in data. So instead of tightly coupling component A to D through B and C, you'd have component A listen to mutations in object X, and component D makes changes to object X. When the change happens, component A gets updated without having to listen to any of the children's $emit functions firing. At first it may seem daunting, but the investment is worthwhile.

Invoke method in child component when the component is changed dynamically from the parent component

I have a simple component hierarchy, in which there is one parent component, which contains the following template <div><component :is="current"></component></div> and two child components, which are dynamically 'switched' out, via the value of current.
The logic for the 'switching' of components is being handled in the parent component. However, when I try to execute a method in the second child component (in response to an event emitted from the first child component, being listened to in the parent component, and altering the value of current in the parent component) through the mounted lifecycle hook, the expected result is not observed.
Essentially, I cannot find a decent way of invoking a child component's methods when that component is 'switched' in as the current component in the parent component.
I have realistically looked at using the $refs and $childrenproperties on the instance, but these do not seem to be of any assistance. I have also reasoned using the event system. I usually 'define' an event listener in the mounted lifecycle hook, however, I refer to the 'issue' of using the lifecycle hooks
What is the usual approach to this situation?
There are two options that immediately come to mind for child components invoking methods on being the "current" child component:
1) Using the mounted lifecycle hook. In order for this to work, you must be using v-if in order to conditionally display the child component, otherwise the child component will not trigger the mounted lifecycle hook. Otherwise, if you're using v-show or some other mechanism for conditionally displaying the child component, the mounted hook will only ever trigger once.
2) Using watched properties. In lieu of the above, you could do something like the following:
<child-component :target_prop="current"></child-component>
Vue.component('child-component', {
. . .,
props: ['target_prop'],
watch: {
target_prop: function() {
if(this.target_prop == your_expected_value) {
//execute the desired method for this component
}
}
}
});
This is, of course, just a proof-of-concept example and there are plenty of alternative ways to use the watched properties to your advantage.
I've also heard of using a "bus" to handle inter-component communication, but I don't believe it would be any better than the above two solutions (and is arguably worse).
Personally, I prefer the mounted lifecycle hook approach, though there's the caveat that any "settings" or data in your child components will be lost on switching between them (although you could also emit a settings object on destruction and store/restore those settings as needed, but that could get messy). You'll have to make the final judgment on which approach better suits your needs and which consequences you're more comfortable dealing with.