nuxt vuex:不要在突变处理程序之外改变 vuex 存储状态

Posted

技术标签:

【中文标题】nuxt vuex:不要在突变处理程序之外改变 vuex 存储状态【英文标题】:nuxt vuex: do not mutate vuex store state outside mutation handlers 【发布时间】:2022-01-09 17:57:19 【问题描述】:

为什么会出现这个错误:

错误 [vuex] 不要在突变处理程序之外改变 vuex 存储状态

当我调用这个组件时会发生这种情况。

 <template lang="pug">
  .auth-popup
    button.auth-popup__button-top.auth-popup__button-top_close(
      type='button'
      aria-label='Закрыть форму авторизации'
      @click='$emit(`close`)'
    )
    h2.auth-popup__title Вход или регистрация

    form.auth-popup__form(@submit.prevent='submitHandler')
      input.auth-popup__fake-input(v-show='showFakeInput' aria-hidden='true' autocomplete='off' ref='fakeInput')

      label.auth-popup__label(for='authLogin') Телефон
      input#authLogin.auth-popup__input(
        type='tel'
        autocomplete='tel'
        v-model='login'
        @input='inputHandler'
        ref='loginInput'
      )

      p.auth-popup__error(v-if='login && !isPhoneAuth') Телефон указан неверно
      p.auth-popup__error(v-if='error' v-html='error')
      p.auth-popup__timer(v-if='getCodeTimer' v-html='codeTimerMessage')

      button.auth-popup__button-send(
        type='submit'
        :disabled='!isLoginLength || !isPhoneAuth || getCodeTimer || showPreloader'
      )
        span.auth-popup__button-inner(v-if='!showPreloader') Получить код
        Preloader.auth-popup__preloader(:show='showPreloader' :color='`#ffffff`')

    button.auth-popup__button-email(
      type='button'
      @click='$emit(`email`)'
    ) Войти по почте
</template>

<script>
import  mapActions, mapMutations, mapGetters  from 'vuex'
import  REGEXPS  from '~/assets/js/utils/constants/regexps';
import  MESSAGES  from "~/assets/js/utils/constants/messages";
import delay from '~/assets/js/utils/functions/promiseTimeout';

import Preloader from "~/components/modules/Preloader"

export default 
  name: 'AuthPhone',
  components: 
    Preloader
  ,
  data() 
    return 
      showFakeInput: false,
      showPreloader: false,
      login: '',
      error: ''
    
  ,
  computed: 
    isPhoneAuth() 
      return REGEXPS.FULL_PHONE_SYMBOLS.test(this.login);
    ,
    isLoginLength() 
      const phoneDigits = this.login.trim().replace(/\D/g, ``);
      return phoneDigits.length > 9;
    ,
    createPhoneValue() 
      let phoneNumber = this.login;
      if (phoneNumber.startsWith('8')) 
        phoneNumber = '7' + phoneNumber.slice(1);
      
      return `+$phoneNumber.replace(/\D+/g, '')`;
    ,
    ...mapGetters(
      getAuthResponse: 'authorization/getAuthResponse',
      getCodeTimer: 'authorization/getCodeTimer',
      codeTimerMessage:'authorization/codeTimerMessage'
    )
  ,
  methods: 
    ...mapActions(
      authRequest: 'authorization/authRequest'
    ),
    ...mapMutations(
      startCodeTimer: 'authorization/startCodeTimer',
      resetCodeTimer: 'authorization/resetCodeTimer'
    ),
    inputHandler() 
      this.error = '';
      if (this.getCodeTimer) 
        this.resetCodeTimer();
      
    ,
    async submitHandler() 
      this.showPreloader = true;
      const sendData = 
        ident_method: `PHONE`,
        login: this.createPhoneValue
      ;
      await this.authRequest(sendData)
        .then(() => 
          this.showPreloader = false;
          const data = this.getAuthResponse;
          if (data.result) 
            if (data.is_registered && !data.is_active) 
              this.error = MESSAGES.ERROR.ACCOUNT_DEACTIVATED;
             else if (data.is_code_sended) 
              this.startCodeTimer(30);
              this.$emit('enter');
            
           else if (MESSAGES.ERROR[data.error]) 
            this.error = MESSAGES.ERROR[data.error];
           else 
            this.error = data.error;
          
        );
    ,

  ,
  mounted() 
    if (this.getAuthResponse.login && this.getAuthResponse.ident_method === `PHONE`) 
      this.login = this.getAuthResponse.login;
    
    this.showFakeInput = true;
    this.$nextTick()
      .then(() => 
        this.$refs.fakeInput.focus();
        return delay(500);
      )
      .then(() => 
        this.$refs.loginInput.focus();
        this.showFakeInput = false;
      );
  ,


</script>

问题就出现在这个突变中——this.startCodeTimer(30);

变异文件:

export default 
  setAuthResponse(state, data) 
    state.authResponse = data
  ,
  setCodeResponse(state, data) 
    state.codeResponse = data
  ,
  setRegResponse(state, data) 
    state.regResponse = data
  ,
  setAuthCode(state, data) 
    state.authCode = data
  ,
  startCodeTimer(state, time) 
    state.newCodeTimer = time
    state.codeTimerId = setInterval(() => 
      if (state.newCodeTimer) 
        state.newCodeTimer--
       else 
        clearInterval(state.codeTimerId)
      
    , 1000)
  ,
  resetCodeTimer(state) 
    state.newCodeTimer = 0
  

如果我理解正确,那么问题就在这里。

state.codeTimerId = setInterval(() => 
      if (state.newCodeTimer) 
        state.newCodeTimer--
       else 
        clearInterval(state.codeTimerId)
      
    , 1000)

但目前还没有解决办法。

【问题讨论】:

【参考方案1】:

问题是在 setInterval 中不能更改状态。 解决方案:创建一个改变状态的突变,并在 setInterval 中调用这个突变。

示例:

 setNewCode(state, count) 
    state.newCodeTimer = count
  ,
  startCodeTimer(state, time) 
    state.newCodeTimer = time
    state.codeTimerId = setInterval(() => 
      if (state.newCodeTimer) 
        this.commit('authorization/setNewCode', time--)
       else 
        clearInterval(state.codeTimerId)
      
    , 1000)
  ,

【讨论】:

我想你的意思是--time,因为现在它会先提交时间然后减去它。 @JasonLandbridge,谢谢,我想是的

以上是关于nuxt vuex:不要在突变处理程序之外改变 vuex 存储状态的主要内容,如果未能解决你的问题,请参考以下文章

在 nuxt 中出现此错误:[vuex] 不要在突变处理程序之外改变 vuex 存储状态

Nuxt / Vue - 不要在突变处理程序之外改变 vuex 存储状态

Vuex - '不要在突变处理程序之外改变 vuex 存储状态'

Vuex 突变引发错误 - 不要在突变处理程序之外改变 vuex 存储状态

错误:[vuex] 不要在突变处理程序之外改变 vuex 存储状态

Vuex 和 VueJS(不要在突变处理程序之外改变 vuex 存储状态)