Home > Enterprise >  How to make this computed property reactive
How to make this computed property reactive

Time:08-03

I've read this guide but can't figure out how to make the computed property canUndo reactive. It does depend on a function call so maybe Vue can't detect the change. Ultimately, I need a solution that doesn't change the function Commands, if it's not possible I'm open to alternative solutions:

function Commands() {
  let commands = [],
    index = -1;
    
  return {
    getIndex: function() {
      return index;
    },
    setIndex: function(i) {
      index = i;
    },
  }
}

var app = new Vue({
  el: '#app',
  data() {
    return {
      commands: new Commands()
    }
  },
  computed : {
    canUndo() {
      console.log('canUndo()')
      return this.commands.getIndex() != -1;
    }
  },
  methods: {
    increment() {
      let index = this.commands.getIndex()
      this.commands.setIndex(index   1)
      console.log(this.commands.getIndex())
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <p>
    <button @click="increment">Increment Index</button>
  </p>
  <p>{{ canUndo }}</p>
</div>

CodePudding user response:

To make it work, index should be a part of data property in Vue instance. Hence, returning index as well inside Commands() function will resolve the issue.

Live Demo :

function Commands() {
  let commands = [];
  return {
    index: -1,
    getIndex: function() {
      return this.index;
    },
    setIndex: function(i) {
      this.index = i;
    },
  }
}

new Vue({
  el: '#app',
  data: {
    commands: new Commands()
  },
    computed : {
    canUndo() {
      console.log('canUndo()')
      return this.commands.getIndex() != -1;
    }
  },
  methods: {
    increment() {
      let index = this.commands.getIndex()
      this.commands.setIndex(index   1)
      console.log(this.commands.getIndex())
    }
  }

})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <p>
    <button @click="increment">Increment Index</button>
  </p>
  <p>{{ canUndo }}</p>
</div>

CodePudding user response:

The issue goes around Vue cannot track down any related changes between your data model and the computed value. The straightforward solution is to keep the current index value in your data model and remove the computed one.

  data() {
    return {
      commands: new Commands(),
      canUndo: false,
    }
  },
  methods: {
    increment() {
      let index = this.commands.getIndex()
      this.commands.setIndex(index   1)
      this.canDo = true;
    },
    decrement() {
      let index = this.commands.getIndex()
      this.commands.setIndex(index - 1)
      this.canDo = this.commands.getIndex() > -1;
    }
  }

In this case, you have to update canDo prop in every situation.

A better solution can be storing the index value as a part of your data model.

  data() {
    return {
      commands: new Commands(),
      cmdIndex: -1,
    }
  },
  computed: {
    canUndo() {    
      return this.cmdIndex != -1;
    }
  },
  methods: {
    increment() {
      this.cmdIndex = this.commands.getIndex()   1;
      this.commands.setIndex(this.cmdIndex)
    },
    increment() {
      this.cmdIndex = this.commands.getIndex() - 1;
      this.commands.setIndex(this.cmdIndex)
    },
  }

By looking around, it's simply unmistakable that there is no need for the Command function at all by storing, incrementing, decrementing, and checking the tmpIndex. I'm not assuming the Command can be removed. However, by removing the Command, your code would be:

  data() {
    return {
      cmdIndex: -1,
    }
  },
  computed: {
    canUndo() {    
      return this.cmdIndex != -1;
    }
  },
  methods: {
    increment() {
      this.cmdIndex  = 1;
    },
    increment() {
      this.cmdIndex -= 1;
    },
  }
  • Related