Vue.js router-view mounted callback - vue.js

I'm using Vue.js with Vue-router in a project and I'm trying to have a callback whenever the routed-to component is ready. Usually you would do it inside each component in the mounted() hook, but for this case I want it for every component that has been routed to.
I tried with router.OnReady() and router.afterEach() but it did not work since they happen after routing but before the component is mounted. I also tried changing the vue-router source code adding mounted() to the router-view component, but it's not getting called.

There is no on-router event for this but according to this issue you can get around this by using Vue.nextTick inside router.afterEach.

Related

removing event listeners in Nuxt/Vue

I'm on Nuxtjs 2.13 and i wanna know "how should I remove event listeners (is there a need??)".
I'm not talkinkg about js addEventListener and removeEventListener . I'm more curious about this.$emit() , $nuxt.$emit() and $nuxt.$on() . is there a way to remove $nuxt.$on() or listener on component <mycomp #myevent="do()" /> in beforeDestroy() and is it necessary?
as my Nuxt project using so much RAM on my server, i kindda think there are some optimization needed.
https://v3.vuejs.org/api/options-lifecycle-hooks.html#unmounted
When this hook (unmounted - OP) is called, all directives of the component instance have been unbound, all event listeners have been removed, and all child component instance have also been unmounted.
However, there is vm.$off which can
Remove custom event listener(s).
https://v2.vuejs.org/v2/api/#vm-off
I saw it used here in a Nuxt context to remove $nuxt.$on listeners:
https://medium.com/#aneesshameed/event-bus-in-nuxt-7728315e81b6
So, if need be, use $nuxt.$off to remove custom events in Nuxt.

What is the difference between the beforeMount and the created lifecycle hook in vuejs

I am still unclear on where I should use the beforeMount and where the created lifecycle hook. It seems to me that in both, the reactive data has been loaded and it is before the DOM has been mounted.
In most cases it doesn't matter whether you use beforeMount or created but there are some where it matters:
Accessing original DOM element your root Vue component is mounting on
can be useful for integration with any server-side rendered framework (php, rails etc.)
explanation and example - When to use the lifecycle method beforeMount in vue.js?
in created hook this.$el is undefined, in beforeMount it's the original unmodified element, in mounted it's root element created by your component/template
Server-side rendering (Nuxt, Vuepress etc.)
docs
beforeCreate and created are only hooks called on the server
that means you should not use any code which needs window, document or any browser API in created as those will not be present on the server
on the other hand code placed in the beforeMount (or mounted) is executed only on the client (browser)
The beforeMount hook runs right before the initial render happens and after the template or render functions have been compiled(when vm.$el has not been created yet).
created is the step after initialization of your component(where you are able to access reactive data and events that are active with the created hook. Templates and Virtual DOM have not yet been mounted or rendered)

<router-view> components inside other <router-view>s (same component)

I currently have the following problem with nested <router-view>s in my app and I want to know if this is even the right way to do it.
I have a navigation.vue route component with child routes configured in the router.
In this component, I have multiple <router-view>s (in a v-for loop).
Every router-view has its own link and if you click on it, the clicked container which holds the router-view will start a transition and reveal the content (the page.vue component).
To fire the transition before confirming the navigation, I listen for the beforeRouteUpdate() hook.
However, I now want to add other navigation components inside this navigation, so that I have something like that:
<navigation>
<page/>
<page/>
<navigation>
<page/>
<page/>
</navigation>
<page/>
</navigation>
The hook to open the sub-navigation seems to work - but if I try to open a page on the second level, the navigation component can't get the $refs that belong to itself. I see the beforeRouteUpdate() hook of the first level navigation being called. I think that's to be expected because it's still in the background, holding the second level navigation and its pages.
What can I do to only use the functionality of the second level navigation when it's opened?
Should I make some checks in the beforeRouteUpdate() hook, and are they both fired?
I'm probably confused because I don't know if the component is being reused or something - in my understanding it should be a second instance of the component.
I'm also using <keep-alive> around the <router-view>s - so if that's a problem and things work differently with that, I'd also be glad to get a hint.
Thanks!
I’m not sure if this will fix your problem but in this vue school video they talk about the Vue Router not always picking up on changes if the same component is being used. You can handle it by adding a key to the router-view like <router-view :key=“$route.path” />. Then any change to the path will trigger a reload of the component. Maybe you can experiment with adding keys to your nested <router-view>s?
I solved it this way:
Both beforeRouteUpdate() hooks are called, so I had to make sure which of the existing navigations should do the work. The upper level navigations skip the hook.
I also needed some checks to only render the navigation in the <router-view> if it is in the $route.match array of the current route.

vue-router reloading App.vue on every new route

I have an App.vue file, which has a vue-router component in it that loads the content of my different pages, like this:
<template>
<div>
<router-view
:auth="auth"
:page_id="page_id"
>
</router-view>
</div>
</template>
I also have some AJAX calls in my created() method, which seem to be triggered every time I load a new page via the router. Is there any way to structure things so that my created() method only gets called once when the application loads, not every time a new page within the router loads?
One approach will be using Navigation Guards when you create a logic to determinate when to make your Ajax calls.
Other will be using Vuex, and create a state object to manage the Ajax calls, dispatch an event when the compontent had been loaded before, and bind a computed property to a getter that will contain the value if that component has been loaded previously.
Solution was a lot simpler than I thought:
The App.vue page was using a href links hard-coded to each route.
If you switch to using
<router-link to="path to your route">text here</router-link>
instead, everything works as normal - but Vue doesn't reload the App.vue component!

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.