VueJS-跳过观察者的第一个更改

Pab*_*lba 2 watch vue-component vuejs2

我正在VueJS中为正在制作的应用程序创建组件,当var更改时,它具有一些监视程序,可将逻辑应用于组件的其他部分。一旦组件被初始化,在用户通过Axios完成一些事件之后,仍然需要服务器上的一些数据来设置它。这些数据从主应用程序发出的事件到达组件。现在的事情是,此var通常会更改(并非总是更改),但是我不希望第一次应用该逻辑,因此我决定设置一个标志并在watcher中检查它是否返回,但是这没有发生:一旦将该标志设置为true(它检查!this.flag),无论如何都会触发观察程序。这是代码:

data(){
    return {
        isSet: false,
        myVar: {
            first: 0,
            second: 0
        }
    }
},
watch: {
    'myVar.first': {
        handler: function(newVal, oldVal){
            if(!this.isSet || other.condition){return}
            console.log('first triggered');
        },
        immediate: false
    },
    'myVar.second': {
        handler: function(newVal, oldVal){
            if(!this.isSet || other.condition){return}
                console.log('second triggered');
        },
        immediate: false
    }
},
methods: {
    setBus(){ // gets called on created(){}
        let self = this;
        Bus.$on('my-event', function(c){
            self.doFirstSet(c);
        });
    },
    doFirstSet(c){
        // do other setting
        if(c.someCondition){
            this.doExtraConfig(c);
        }
        this.isSet = true; // at this point is when the watchers get triggered
    },
    doExtraConfig(c){
        // do more stuff
        if('first' in c){
            this.myVar.first = c.first;
        }else if('second' in c){
            this.myVar.second = c.second;
        }
        console.log("watchers don't get triggered yet");
    }
}
Run Code Online (Sandbox Code Playgroud)

有什么想法如何在标志更改时阻止他们开火?

小智 28

您可以使用实例的$watch()方法在组件中的任何一点开始观察数据元素。这样,观察者就不会在 Vue 实例的实例化时实例化,正如文档指定的那样:

Vue 实例将在实例化时为 [watch] 对象中的每个条目调用 $watch()。

所以,你可能会寻找这个:

data: {
  return() {
    data: null,
  };
},

mounted() {
  api.fetchList().then((response) => {
    this.data = response.dataFetched
    this.$watch('data', this.dataWatcher);
  });
},

methods: {
  dataWatcher() {
    // Code won't execute after this.data assignment at the api promise resolution
  },
}
Run Code Online (Sandbox Code Playgroud)

在像这样的简单情况下,Badgy 的反应更加直接,尽管您可以避免该doneFetching变量。$watch()如果我需要更多控制,我会使用它:它实际上返回一个“unwatch”函数,你可以调用它来删除它(检查出来)。

还要记住,观察者应该用于边缘情况,并避免在其他观察者中改变观察到的变量。如果不小心使用,这可能会损害 Vue 反应性在数据和方法之间的“正交性”。

  • 我同意@yououuri,并给这个答案的作者带来了一点推动。:-) (2认同)

小智 15

Badgy 的回应似乎不那么具有侵入性,也不太容易出错。

我们项目中使用的久经考验的方法,特别是用于跟踪更改的方法,如下所示:

export default {
  data: () => {
    dataLoaded: false,
    valueThatChanges: 'defaultValue',
  },
  mounted () {
    let self = this
    loadData().then((result) => {
      self.valueThatChanges = result
      self.$nextTick(() => { //with this we skip the first change
        self.dataLoaded = true
      })
    })
  },
  methods: {
    loadData() {
      //your implementation
      return result
    }
  },
  watch: {
    valueThatChanges: function(newValue, oldValue) {
      if (this.dataLoaded) {
        //send tracking change
        console.log('Value was changed from ' + oldValue + ' to ' + newValue + ' via interaction, not by loading')
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 我认为“let self = this”是没有必要的。箭头函数保留外部作用域中“this”的值。 (3认同)

Bad*_*dgy 5

您应该只声​​明一个布尔变量,该变量定义是否完成了数据提取。默认情况下,将其设置为false doneFetching: false,一旦完成提取逻辑,就调用this.doneFetching = true

之后,您在观察器中所要做的只是if(this.doneFetching){...} 简单而干净的。此简单的逻辑应该可以防止在需要之前触发观察器逻辑。