38

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?

Artur Grigio
  • 4,639
  • 7
  • 40
  • 61

4 Answers4

72

Your watch should look like this.

watch: {
    searchStr: _.debounce(function(newVal){
      this.checkSearchStr(newVal)
    }, 100)
},

This is a bit unusual, however. I don't see why you would want to debounce a watch. Possibly you would rather just debounce the checkSearchStr method.

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

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

One other thing I would like to point out; no where in the code is searchStr defined. When you watch a value with Vue, you are watching a data or computed property. As you have currently defined it, the watch on searchStr will never execute.

Bert
  • 76,566
  • 15
  • 189
  • 159
  • 6
    I think that the `this` (this.foo) inside the function isnt the VueJS. – rogeriolino Jul 18 '17 at 23:37
  • 1
    @rogeriolino Thats not correct. When a component is instantiated, the method is bound to the component. In other words, `this` *will* be the Vue. – Bert Jul 18 '17 at 23:38
  • 1
    I just found the Vue.js documentation for `debounce` (docs - https://vuejs.org/v2/guide/migration.html#debounce-Param-Attribute-for-v-model-removed). Thanks for your answer (part 2), it was very helpful. I should not be running `debounce` on the watched element. – Artur Grigio Jul 18 '17 at 23:56
  • 1
    hmm.. I think the code can be shorter: watch: { searchStr: "checkSearchStr" } source: https://www.youtube.com/watch?v=7YZ5DwlLSt8&feature=youtu.be&t=4m35s – Hiep May 16 '18 at 16:45
  • 1
    @Hiep Sure, that is documented in the API. https://vuejs.org/v2/api/#watch – Bert May 16 '18 at 17:36
  • Just make the 'fetch data' function debounce. Cuz thats where u wanna take the load of. – Cas Bloem Aug 28 '18 at 14:50
0

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)
}
Adam Cox
  • 2,899
  • 1
  • 32
  • 37
0

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)
}
tao
  • 69,335
  • 13
  • 103
  • 126
-1

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)
}
chickens
  • 14,980
  • 4
  • 51
  • 50