【问题标题】:VueJS - Skip watcher's first changeVueJS - 跳过观察者的第一个变化
【发布时间】:2019-03-09 07:51:21
【问题描述】:

我正在 VueJS 中为我​​正在制作的应用程序创建一个组件,当我的 var 更改时,它有一些观察者将逻辑应用于组件的其他部分。一旦组件被初始化,它仍然需要通过用户通过 Axios 完成的一些事件后来自服务器的一些数据来设置。此数据从主应用程序发出的事件中获取到组件。现在问题是这个 var 通常会发生变化(并非总是如此),但我不希望第一次应用这个逻辑,所以我决定设置一个标志并在观察者中检查它是否返回,但它没有发生:一旦我将该标志设置回真(它检查!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");
    }
}

知道如何在标志更改时阻止它们发射吗?

【问题讨论】:

    标签: vuejs2 vue-component watch


    【解决方案1】:

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

    【讨论】:

    • 我认为let self = this 是不必要的。箭头函数从外部范围保留this 的值。
    【解决方案2】:

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

    "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
      },
    }
    

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

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

    【讨论】:

    • 这比使用布尔值更好,因为可以在布尔值更改后异步调用手表回调。
    • 我同意@yooouuri 并为这个答案的作者提供了一点帮助。 :-)
    【解决方案3】:

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

    之后,您在观察者中要做的就是干净而简单的if(this.doneFetching){...} 这个简单的逻辑应该可以防止你的观察者逻辑在你想要它之前被触发。

    【讨论】:

    • 我担心它在很多情况下都不起作用,观察者回调(除非立即?)通常在方法设置标志完成后执行,而不是在值实际更改时执行。
    猜你喜欢
    • 2019-04-22
    • 2018-04-18
    • 1970-01-01
    • 2018-12-11
    • 2019-08-18
    • 2018-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多