当 ref 的值发生变化时,Vue 不会更新模板 Vue 3

Posted

技术标签:

【中文标题】当 ref 的值发生变化时,Vue 不会更新模板 Vue 3【英文标题】:Vue doesn't update the template when the value of ref changes Vue 3 【发布时间】:2021-11-21 19:03:51 【问题描述】:

上下文:我希望在注册操作运行后显示进度条。但是返回 isLoading 中的计算函数并没有反映 DOM 中的变化

问题:我正在尝试在发出返回请求时模拟加载。而且我的变量(isLoading)在模板或 DOM 中没有改变。

<template>
  <div class="p-fluid p-card custom-login-box">
    <div class="p-card-header p-py-2">
      <div class="p-card-title p-text-center">t('login_signUp')</div>
      <div class="p-card-subtitle p-text-center">t('sign_up_subtitle')</div>
    </div>
    isLoading
    <div v-show="isLoading">
      <ProgressBar mode="indeterminate" style="height: .2em" />
    </div>
    <div class="p-card-body">
      <form>
        <div class="p-field p-mb-3">
          <div class="p-col-12">
            <span class="p-float-label p-input-icon-left">
              <i class="pi pi-id-card"></i>
              <InputText
                id="fullName"
                v-model="fullName"
                type="text"
                name="fullName"
                autocomplete="fullName"
                :class=" 'p-invalid': errors.fullName "
              />
              <label for="fullName">t('sign_up_full_name')</label>
            </span>
            <div class="p-error p-ml-5"> errors.fullName </div>
          </div>
        </div>
....
</template>
<script lang="ts">
  import  defineComponent, computed, ref  from 'vue'
  import  useI18n  from 'vue-i18n'
  import * as yup from 'yup'
  import  useField, useForm  from 'vee-validate'
  import  msg  from '@/plugins/toast'

  export default defineComponent(

    setup () 
      const  t  = useI18n()
      const state = ref(false)

      const validationSchema = computed(() => 
        return yup.object(
          fullName: yup.string().required(t('required')),
          email: yup.string().required(t('required')).email(t('emai_invalid')),
          password: yup.string().required(t('required')).matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.8,)/, t('must_comply_suggestion')),
          confirmPassword: yup.string().oneOf([yup.ref('password'), null], t('matches_password')).required()
        )
      )

      const  errors, meta  = useForm( validationSchema )

      const  value: fullName  = useField<string>('fullName')
      const  value: email  = useField<string>('email')
      const  value: password, meta: metaPassword  = useField<string>('password')
      const  value: confirmPassword  = useField<string>('confirmPassword')

      const register = async () => 
        console.log('valor inicial en loading', state.value)
        console.log('entro a la funcion')
        state.value = true
        console.log('el valor que le asigno a loading', state.value)
        await setTimeout(() => 
          const res:number = Math.round((Math.random() * (2 - 1) + 1))
          if (res === 1) 
            msg.showSuccess()
           else 
            msg.showError(t('exist_email'))
          
        , 2000)
        state.value = false
        console.log('despues que termina la funcion', state.value)
      

      return  t, fullName, email, password, confirmPassword, errors, meta, metaPassword, register, isLoading: computed(() => state.value) 
    
</script>

【问题讨论】:

您是否使用 Vue 开发工具确认 isLoading 不会更改状态? v-show 是出了名的敏感,通常它没有在 DOM 中更新的原因不是状态没有改变(根据我的经验)。不过,这里无法确定可能出了什么问题。 你为什么还要在那里使用计算,而不是直接调用 ref isLoading 并直接使用它? 【参考方案1】:

问题是await 是基于 Promise 的(只能与 Promise 一起使用)并且 setTimeout 不返回 Promise

因此,当register 方法执行时,它首先将state.value 设置为true,然后安排超时并立即state.value 设置为false。要使其工作,请将state.value = false 移动到setTimeout 回调中。

由于您仅使用 setTimeout 来模拟异步调用,因此当您将 setTimeout 替换为基于 Promise 的真实异步调用(例如 fetch)时,代码将按预期工作...

【讨论】:

以上是关于当 ref 的值发生变化时,Vue 不会更新模板 Vue 3的主要内容,如果未能解决你的问题,请参考以下文章

Vue 中视图更新

Vue3全家桶升级指南二reftoReftoRefs的区别

Vue.js 计算属性

Vue.js 计算属性

Vue.js 计算属性

vue: 关于多路由公用模板,导致组件内数组缓存问题