简体   繁体   中英

How to correctly use Vue JS watch with lodash debounce

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?

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.

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)
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM