Why do I need a Vue component: a key?

I have a small Vue.js component that displays a favorite star icon. Clicking on the favorite / uneven item icon. So far, I have only implemented a part of the user interface that looks like this:

<template> <div :key="favorite"> <a v-on:click="toggleFavorite" style="cursor: pointer"> <i v-show="favorite" class="text-warning fas fa-star"></i> <i v-show="!favorite" class="text-warning far fa-star"></i> </a> </div> </template> <script> export default { data() { return { favorite: true, } }, mounted() { }, methods: { toggleFavorite() { this.favorite = !this.favorite } }, props: ['team-id'], } </script> <style scoped> </style> 

As you can see, the logic is pretty simple.

This works well, but one thing that bothers me is that if I remove the :key property from my template, the icon will not refresh when I click on it (although I checked that the underlying property was indeed updated correctly). Addendum :key makes it work, I think, because it makes Vue.js completely re-render the component when updating favorite .

Why is this happening? I am new to the world of JS frameworks, so please forgive any obvious things that might be missing. I did some research on the Internet, but could not find an explanation. I just want to make sure I'm doing everything right, and not just crack the problem.

+5
source share
4 answers

This seems to be a common FontAwesome CSS issue regardless of structure. There is a problem with github, and here is the same problem with the reaction https://github.com/FortAwesome/Font-Awesome/issues/11967

To prove this, here is a simplified version of the same example, but using bootstrap icons

 new Vue({ el: '#app', data() { return { fav: true } } }); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js" ></script> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> <div id="app"> <div> <a v-on:click="fav = !fav" style="cursor: pointer"> <i v-show="fav" class="glyphicon glyphicon-star"></i> <i v-show="!fav" class="glyphicon glyphicon-star-empty"></i> </a> </div> </div> 
+2
source

Vue patches with virtual DOM whenever needed. That is, whenever vue detects changes in the DOM, it patches them to improve performance. And a fix in the DOM will not change the icon or image. Instead, you need to replace the DOM.

Thus, vue provides us with a way when we need to change the DOM, replacing the method, we can use the binding :key .

So, the binding :key can be used to force the replacement of an element / component instead of reusing it.

The following entire html div will be replaced whenever there is a change in favorite , since we :key bind to it:

 <div :key="favorite"> <a v-on:click="toggleFavorite" style="cursor: pointer"> <i v-show="favorite" class="text-warning fas fa-star"></i> <i v-show="!favorite" class="text-warning far fa-star"></i> </a> </div> 

This is why vue forcibly allows us to use the binding :key inside the loop, since it is necessary to replace the elements inside the loop whenever it detects changes in data . This is mandatory for 2.2.0+ , and ESLint also implements this function so that if you miss the :key binding inside the loop, then you will see an error on this line when you use an editor that supports eslint so that you can fix the error.

Just an opinion, a strict binding requirement :key must be removed from vue, because we may need a predefined data loop and don't want to change the DOM, but we still use the v-for loop to list big data. But this may be a rare case.


Read the documentation carefully for: key bindings , and then you get an idea.

Binding :key can be useful if you want:

Properly run component lifecycle hooks

Trigger transitions


  • Use :key binding to replace the DOM. Remember that this is a slower performance since it replaces the entire DOM associated with the element.
  • Do not use the :key binding if you do not want to replace the DOM or you think that there is no need to detect changes to data . This will let vue work better without binding :key .
+2
source

Good. I think the problem is that you are changing your root data object. To maintain responsiveness, you should not modify the root data object after you create the Vue instance.

Here is your code in plain Vue. I don't need: a key to make it work. I would save: a key for internal loops.

Markup

 <div id="vueRoot"> <a v-on:click="toggleFavorite" style="cursor: pointer"> <i v-show="store.favorite" class="text-warning fas fa-star">Fav</i> <i v-show="!store.favorite" class="text-warning far fa-star">Not fav</i> </a> </div> 

code

 vm = new Vue({ el : "#vueRoot", data() { return { store :{ favorite: true }} }, mounted() { }, methods: { toggleFavorite() { this.store.favorite = !this.store.favorite } } } ); 

This is a working example with minimal changes. From what you showed us, you should just have a <i> element, and then do what you want with a dynamic list of classes, for example ...

 <i :class="['text-warning','fa-star',store.favorite?'fas':'far']"></i> 
+1
source

You do not need a key: it is needed only in v-for loops. I suggest you remove it and replace v-show with the v-if and v-else directive.

  <i v-if="favorite" class="text-warning fas fa-star"></i> <i v-else class="text-warning far fa-star"></i> 

v-if deletes and adds the section to the DOM, while v-show just hides it, so this method solves your problem

+1
source

Source: https://habr.com/ru/post/1275519/


All Articles