Vuex 观察者错误地触发了两次

Posted

技术标签:

【中文标题】Vuex 观察者错误地触发了两次【英文标题】:Vuex watcher wrongly firing twice 【发布时间】:2020-02-21 07:02:21 【问题描述】:

我已经搜索了 2 个小时,我对自己做错了什么一无所知.. 希望有人可以帮助我:

基本上这很容易。我有一个可重用的 Recaptchas 组件。 有问题的元素是“忘记密码”弹出对话框中的文本字段(通过登录掩码)

处理不同验证码的基本思路(因为同一页面上有两个)是:

我为每个可能的验证码都有一个 vuex 字段,初始化为null 对于每个表单提交按钮,我触发了一个突变,将验证码字段设置为0 然后我在 recaptcha 组件中设置了监听器来监听变化,if === 0,开始评估验证码 然后onValidated,调用一个将结果保存到vuex的突变。另一个 if(newVal) 的观察者然后提交整个事情。

在我的理论中,这没有问题。我记得它在过去的某个时候已经工作过(或者我只是没有注意到双重提交),但现在我做了一些改变,它的行为真的很奇怪。

确切地说:我单击按钮一次,一切正常,但一个观察者触发了两次,即使它根本不应该。 之前的所有东西都会触发一次,只有那个观察者会触发两次,即使我这样做了

if (!this.running) 
            this.running = true
            console.log('forgot watcher 2')
            this.$refs.recaptcha.execute()
        

但它也不起作用。它似乎在完全相同的时间运行它们,这对我来说没有意义

控制台输出是这样的:

submit
verify forgot captcha
0
forgot watcher 2
0
forgot watcher 2
verified
forgot captcha verified 03AOLTBLTP...............
forgot watcher
verified
forgot watcher

以一种易于理解的方式:

点击 login.vue mutation 将值设置为 0 recaptcha.vue 中的观察者注意到并开始评估(这个错误触发了两次) 如果验证,verifyCaptcha() recaptcha.vue 存储到 vuex

我的文件如下:

login.vue

<template>
  <v-form
    @submit.prevent="twoFaRequired ? sendTwoFa() : verifyLoginCaptcha()"
  >
    // ...
   <recaptcha />
    // ...
    <v-layout>
        <form>
           // ...
           <recaptcha />
           <v-btn
              color="primary"
              :loading="forgotLoading"
              :disabled="successful || forgotLoading || $v.$invalid"
              @click.native.stop.prevent="verifyForgotCaptcha"
            >Reset Password</v-btn>

//...
  methods: 
    verifyForgotCaptcha() 
      console.log('submit')
      this.$store.commit('user/VERIFY_FORGOT_CAPTCHA')
    ,
//...
  watch: 
    forgotCaptcha(newVal, oldVal) 
      if (newVal) 
        console.log('forgot watcher')
        this.sendForgotEmail()
      
    ,
//...
    forgotCaptcha() 
      return this.$store.state.user.forgotCaptcha
    ,

mutations.js

//...
  VERIFY_FORGOT_CAPTCHA(state) 
    console.log('verify forgot captcha')
    state.forgotCaptcha = 0
  ,
  FORGOT_CAPTCHA_VERIFIED(state, payload) 
    console.log('forgot captcha verified', payload)
    state.forgotCaptcha = payload
  ,
//...

recaptcha.vue

<template>
  <div class="d-flex justify-center">
    <vue-recaptcha
      ref="recaptcha"
      :sitekey=siteKey
      :loadRecaptchaScript="true"
      size="invisible"
      @verify="verifyCaptcha">
    </vue-recaptcha>
  </div>
</template>

<script>
  import VueRecaptcha from 'vue-recaptcha'
  import  mapGetters  from 'vuex'

  export default 
    data: () => (
      running: false,
      usage: '',
      siteKey: 'xxxxxxx'
    ),
    components:  VueRecaptcha ,
    computed: 
      ...mapGetters([
        'user'
      ]),
    //...
      isForgotCaptcha() 
        return this.$store.getters['user/forgotCaptcha']
      
    ,
    methods: 
      verifyCaptcha(response) 
        console.log('verified')
    //...
          if (this.usage === 'forgot')        this.$store.commit('user/FORGOT_CAPTCHA_VERIFIED', response)
        this.usage = ''
        this.$refs.recaptcha.reset()
      
    ,
    watch: 
    //...
      isForgotCaptcha(newVal) 
        if (newVal === 0) 
          console.log('forgot watcher 2')
          this.usage = 'forgot'
          this.$refs.recaptcha.execute()
        
      ,
    
  ;
</script>

如果您需要更多信息/代码,请随时询问。我希望有人能告诉我我做错了什么。我要疯了。 谢谢!

【问题讨论】:

【参考方案1】:

login.vue 中有两个&lt;recaptcha&gt; 实例。它们中的每一个都有自己的一组观察者,它们不是共享的。同样,它们每个都有自己的计算属性isForgotCaptcha

user/forgotCaptcha 改变时,它会改变两个组件的isForgotCaptcha 属性,触发它们的每个观察者。

设置this.running 只会为recaptcha 组件之一设置该属性,不会对另一个组件产生任何影响。

【讨论】:

哇,好吧,这听起来很合理。有趣的!应该是这个问题,谢谢!这就解释了为什么我的守卫没有任何效果,而那些观察者似乎同时跑了!你知道我怎么能把它们分开吗?或者我怎样才能做到这一点?

以上是关于Vuex 观察者错误地触发了两次的主要内容,如果未能解决你的问题,请参考以下文章

在观察者中出现 Vuex 错误,但我没有使用 Vuex [Nuxt]

如何避免两次调用observe()?

keyboardWillShow fire 两次

NodeJS文件系统两次或更频繁地观察抛出事件

在 vuex 中设置 firebase.User 会导致永恒循环

错误:达到 10 次 $digest() 迭代。中止!在最后 5 次迭代中触发的观察者:过滤器中的 []