【问题标题】:reactive object not updating on event emitted from watch反应对象不更新从手表发出的事件
【发布时间】:2021-01-19 17:54:39
【问题描述】:

我正在使用这个响应式 obj 构建一个复杂的表单

    const formData = reactive({})
    provide('formData', formData)

在表单中,其中一个组件呈现如下:

      <ComboZone
          v-model:municipality_p="formData.registry.municipality"
          v-model:province_p="formData.registry.province"
          v-model:region_p="formData.registry.region"
        />

这是 ComboZone 渲染函数:

     setup(props: any, { emit }) {
        const { t } = useI18n()
    
        const { getters } = useStore()
        const municipalities = getters['registry/municipalities']
        const _provinces = getters['registry/provinces']
        const _regions = getters['registry/regions']
    
        const municipality = useModelWrapper(props, emit, 'municipality_p')
        const province = useModelWrapper(props, emit, 'province_p')
        const region = useModelWrapper(props, emit, 'region_p')
    
        const updateConnectedField = (key: string, collection: ComputedRef<any>) => {
          if (collection.value && collection.value.length === 1) {
            console.log(`update:${key} => ${collection.value[0].id}`)
            emit(`update:${key}`, collection.value[0].id)
          } else {
            console.log(`update:${key} =>undefined`)
            emit(`update:${key}`, undefined)
          }
        }
    
        const provinces = computed(() => (municipality.value ? _provinces[municipality.value] : []))
        const regions = computed(() => (province.value ? _regions[province.value] : []))
    
        watch(municipality, () => updateConnectedField('province_p', provinces))
        watch(province, () => updateConnectedField('region_p', regions))
    
        return { t, municipality, province, region, municipalities, provinces, regions }
      }

使用模型包装器:

import { computed, WritableComputedRef } from 'vue'
export default function useModelWrapper(props: any, emit: any, name = 'modelValue'): WritableComputedRef<any> {
  return computed({
    get: () => props[name],
    set: (value) => {
      console.log(`useModelWrapper update:${name} => ${value}`)
      emit(`update:${name}`, value)
    }
  })
}

问题是useModelWrapper发出的事件正确更新了父模板中的formData,watch函数内部发出的事件延迟了一次渲染......

【问题讨论】:

  • 您应该在codesanbox.io 之类的实用程序中放置一个最小可重现的问题示例。我无法重现您的问题,即它在我的机器上工作????????

标签: vue.js vuejs3 vue-composition-api


【解决方案1】:

TL;DR;

使用watchEffect 代替watch


...需要注意的是,我没有尝试重现,我的猜测是您遇到了这个问题,因为您使用的是watch,它懒惰地运行惰性性质是延迟执行的结果,这可能是您看到它在下一个周期触发的原因。

watchEffect

在响应式跟踪其依赖关系的同时立即运行一个函数,并在依赖关系发生变化时重新运行它。

watch

与 watchEffect 相比,watch 允许我们:

  • 懒惰地执行副作用;
  • 更具体地说明应该触发观察者重新运行的状态;
  • 访问被监视状态的先前值和当前值。

【讨论】:

  • 轻度相关,solidjs 框架的作者有一条关于各种框架的更新行为的推文很有趣:twitter.com/RyanCarniato/status/1353801009844240389
  • 嗨,Daniel,watchEffect 不能正常工作,我想我在 watch 函数中使用 { flush: 'post' } 找到了解决方案,因为在同一个刻度中有多个更新,而且正如你所说手表很懒
【解决方案2】:

找到了解决方案,但 watchEffect 不是办法。 看起来是在同一滴答声中出现多个更新事件的问题,这对我使用 { flush: 'post' } 作为手表功能的选项处理手表的刷新很有用。

【讨论】:

    【解决方案3】:

    尝试在组件中使用 key: prop。我认为它会解决问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-05-23
      • 2021-04-13
      • 2015-05-27
      • 2016-09-03
      • 2019-10-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多