Vue computed property not updating as expected

Kylie picture Kylie · Sep 24, 2017 · Viewed 8.2k times · Source

I have a count

  You have {{ keywordsLeft }} keywords left

and in my Vue.

var u = new Vue({
    el:'#app',
    data:{
        keywords:keywords,
        user:user,
        total_keywords:user.total_keywords,
    },
    computed: {
        keywordsLeft: function () {
           var left = total_keywords-keywords.length;
           if(left<=0){
             return 0;
           } else {
             return left;
           }
       }
   }, 
   methods: {
       deleteKeyword: function(keyword){
           var i = this.keywords.indexOf(keyword);
           this.keywords.splice(i,1);
       }
   }
       // rest of VUE code.

Whenever an update is made to the data, the computed value doesnt update. I have to refresh the page to do it. I thought the purpose of computed property was live reactivity? Am I missing something?

Do I need to explicitly update it somehow? recompute is manually? Forgive me if Im being stupid, but this seems like a waste if its not done automatically. Might as well just use jquery then lol

Answer

pate picture pate · Sep 24, 2017

Computed properties are computed automatically and they're what you're supposed to use in a case like this.

I guess the problem lies somewhere in the code that updates your actual data. It is doing it in a way that doesn't work with Vue's reactivity system. This happens to many people :)

I suggest you to read this for overall guide https://vuejs.org/v2/guide/reactivity.html and this https://vuejs.org/v2/guide/list.html#Array-Change-Detection for gotchas on arrays.

Added:

I see your problem now. Inside the keywordsLeft computed property you're not referring to the Vue instance's data but actually to the original data. What I mean the keywords.length refers to the original keywords object and its length. Same with total_keywords - it doesn't refer to the Vue instance's data. You should use this.keywords and this.total_keywords.

I always keep the instance data property names different from the outside/global/not-Vue data. I'm saying something like this is better:

data: {
  myKeywords: keywords,
  myTotalKeywords: totalKeywords
  ...
}

This way you cannot mix what you're referring to. Now you should refer to this.myKeywords etc. inside the Vue instance's scope.