How to correctly use Vue JS watch with lodash debounce

Viewed 34715

I'm using lodash to call a debounce function on a component like so:

...
import _ from 'lodash';

export default {
    store,
    data: () => {
        return {
            foo: "",
        }
    },

    watch: {
        searchStr: _.debounce(this.default.methods.checkSearchStr(str), 100)
    },

    methods: {
        checkSearchStr(string) {
            console.log(this.foo) // <-- ISSUE 1
            console.log(this.$store.dispatch('someMethod',string) // <-- ISSUE 2
        }
    }
}
  • Issue 1 is that my method checkSearchStr doesn't know about foo
  • Issue 2 is that my store is undefined as well

Why doesn't my method know this when called through _.debounce? And what is the correct usage?

5 Answers

All the examples shown in the answers and in the Vue documentation are actually not very good because all instances of your component will share a single debounce method. This means that if you have 2 instances of the component on a single page and they both fire the debounced method within the 100ms window only 1 of the 2 components will work.

Now in most scenarios this is probably fine since it's a more niche issue but if you do run into this issue it's safer to create the debounce methods within your components created() so that it's instance specific.

  created() {
    this.$watch('checkSearchStr', _.debounce(function(string) {
      console.log(this.foo)
      console.log(this.$store.dispatch('someMethod',string))
    }, 100));
  }

As @Bert mentioned in comments this scope is local to the function. Therefore, to make this scope to properties in data, change to:

methods: {
    checkSearchStr: _.debounce((string) => {
        console.log(this.foo) 
        console.log(this.$store.dispatch('someMethod',string)) 
    }, 100)
}

Since it needs to call methods defined in the outer scope, the debounced function looks like the perfect candidate for an arrow function:

watch: {
  searchStr: 'checkSearchStr'
},
methods: {
  checkSearchStr: _.debounce(val => {
    // `this` is the component instance (a.k.a. outer `this`)
    console.log(this)

    this.$store.dispatch('someMethod', val); 
  }, 100)
}

The right way to use debounce while being able to use this inside the function:

watch: {
    searchStr(newVal){
      this.checkSearchStr(this, newVal)
    }
},

methods: {
    checkSearchStr: _.debounce(function(self, newVal) {
        console.log(self.foo) 
        console.log(self.$store.dispatch('someMethod',newVal)) 
    }, 100)
}
Related