Basically, I want to keep alive 2 components in router-view and it works, however, I don't know if I am doing it correctly.
<keep-alive include="users, data">
<router-view></router-view>
</keep-alive>
users and data are route names. Is this correct way to do it. Are there any disadvantages of keep-alive?
The only disadvantage is that these components are kept in memory and therefore their state is saved and not reset.
You also lose lifecycle hooks like created, mounted, etc. since the component is not being rebuilt from scratch anymore. You can replace those lifecycle hooks with hooks that are specific to keep-alive components. For example:
https://v2.vuejs.org/v2/api/#activated
Whether keep-alive is a disadvantage or advantage is entirely up to your scenario. If you want to keep the state because you want to switch fast and often between the keep-alive components, it could be an advantage. If you really rely on a clean state through components being built and destroyed, it could be a disadvantage.
1. We can achieve it by using
<keep-alive>
// Render component inside
</keep-alive>
special tag which has provided by vueJs.
2. use life cycle hooks:
a. activated()
b. deactivated()
Related
I am looking for information on where Vue stores the cached component data when a component is wrapped in the keep-alive component. I looked at the local storage, cache storage, and session storage but I don't see anything obvious. I suspect that the cache is stored in the DOM but I was hoping that someone might know for sure or offer some clarification.
The issue I am having is that I have some Vue components that I am wrapping as web components using https://github.com/vuejs/vue-web-component-wrapper. This library is responsible for adding the keep-alive to my vue components. These components are then used inside other front end frameworks. The keep alive doesn't work as expected in this scenario, if I navigate away from the component and return the component is not restored to it's previous state. What I am expecting to happen is that navigation away from the component and returning restores the component to it's previous state as described in https://v2.vuejs.org/v2/guide/components-dynamic-async.html
After some digging around - in the implementation of keep-alive (Here).
You can see that the cache is stored locally on the component level, meaning that if the <keep-alive> is removed from the DOM it will lose its stored cache.
In theory, if you need it another way you may extend the component - create a prop like cacheName that you pass down to it. Have on mounted check if there is anything in localStorage for that prop to supplement it. Then add a watcher (deep) to watch for changes to the cache and store it in LocalStorage with the key coming for cacheName.
Some rough code of how the component may look - Here. Keep in mind that it may not be possible to get the object from Vue this way so you may need to copy the whole thing then add the code on top of it.
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.
Let's say there is a global component BIcon.vue available everywhere.
And another component, but regular not global, called BIconFake.vue.
We can override BIcon.vue by BIconFake.vue like that:
<template>
<div>
<b-icon icon="plus"><!-- <- Here is it BIconFake component! -->
</div>
</template>
<script>
import BIcon from '~/components/BIconFake'
export default {
components: {
BIcon // <- BIconFake component inside!
}
}
</script>
By this way, Vue.js will display BIconFake component instead of regular BIcon component.
I tried to pass props, events or attributes and it works like expected.
Vue.js is awesome... and big. Really, I don't know everything about it, and I don't want to see side effects or unexpected behavior when doing this override.
So, I want to know if it's safe to do that? Does it make a mess in Vue.js instance? What about memory?
we can override component with pure vue.js. Also, I made this example for Buefy, but we can do that with any UI frameworks like Quasar, Vuetify...
Thinking globaly, Is it good to override components of UI frameworks? What about security, scalability and maintenability?
In fact, I searched a way to build a plugins or addons system to my Nuxt.js app, like wordpress plugins.
Is it a good architecture to start building my app by overriding vue component? Is there another way to build app addons for vue, by using npm or webpack?
If you are going to wrap existing components like that then you should keep in mind the Liskov substitution principle. <b-icon-fake> can likely be used in place of <b-icon> provided that it:
accepts the same props
emits the same events
exposes the same public methods (if it is used with a ref)
behaves in the same way
Most of those points probably do not apply for a simple <b-icon> component.
Also keep in mind the template of your wrapped component now includes an extra <div> around it. This can interfere with styling and things like that.
You can eliminate the additional memory overhead by using a functional component instead, but you will need to write the render function manually to preserve the behavior of the wrapped component. But honestly I wouldn't worry too much about memory usage unless you have determined it to be an issue (after profiling your app).
In terms of whether it is "good" to do this or not, I can't say. There are advantages and disadvantages. In my opinion, wrapping components is fine as long as you are the only consumer of the wrapper component and doing so doesn't affect any existing usage of the wrapped component outside of your code.
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.
I have a listing/detail use case, where the user can double-click an item in a product list, go to the detail screen to edit and then go back to the listing screen when they're done. I've already done this using the dynamic components technique described here: https://v2.vuejs.org/v2/guide/components.html#Dynamic-Components. But now that I'm planning to use vue-router elsewhere in the application, I'd like to refactor this to use routing instead. With my dynamic components technique, I used keep-alive to ensure that when the user switched back to the list view, the same selection was present as before the edit. But it seems to me that with routing the product list component would be re-rendered, which is not what I want.
Now, it looks like router-view can be wrapped in keep-alive, which would solve one problem but introduce lots of others, as I only want that route kept alive, not all of them (and at present I'm just using a single top level router-view). Vue 2.1 has clearly done something to address this by introducing include and exclude parameters for router-view. But I don't really want to do this either, as it seems very clunky to have to declare up front in my main page all the routes which should or shouldn't use keep-alive. It would be much neater to declare whether I want keep-alive at the point I'm configuring the route (i.e., in the routes array). So what's my best option?
You can specify the route you want to keep alive , like:
<keep-alive include="home">
<router-view/>
</keep-alive>
In this case, only home route will be kept alive
Vue 3
<router-view v-slot="{ Component }">
<keep-alive>
<component :is="Component" />
</keep-alive>
</router-view>
Exactly as is, you don't need a Component attribute in the App.vue. Also your this'll work even if your components don't have a name property specified.
I had a similar problem and looked at Vuex but decided it would require too much changes/additions in my code to add to the project.
I found this library https://www.npmjs.com/package/vue-save-state which solved the problem for me, keeping the state of 1 component synchronized with localStorage, and it only took a few minutes and a few lines of code (all documented in the Github page of the package).
One solution without localStorage:
import {Component, Provide, Vue} from "vue-property-decorator";
#Component
export default class Counter extends Vue {
#Provide() count = 0
/**
* HERE
*/
beforeDestroy() {
Object.getPrototypeOf(this).constructor.STATE = this;
}
/**
* AND HERE
*/
beforeMount() {
const state = Object.getPrototypeOf(this).constructor.STATE;
Object.entries(state || {})
.filter(([k, v]) => /^[^$_]+$/.test(k) && typeof v !== "function")
.forEach(([k]) => this[k] = state[k]);
}
}
What seems to me is you are looking for some kind of state management. If you have data which is shared by multiple components and you want to render component in different order, but dont want to load data again for each component.
This works like following:
Vue offers a simple state management, but I will recommend to use Vuex which is a standard for state management among vue community.