反应对象不更新手表发出的事件
reactive object not updating on event emitted from watch
我正在使用这个反应对象构建一个复杂的表单
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 函数内部发出的事件被一个渲染延迟了....
尝试在组件中使用key:prop。我认为它会解决问题。
TL;DR;
使用watchEffect
代替watch
...请注意,我没有尝试重现,我的猜测是您 运行 遇到了这个问题,因为您使用的 watch
运行 懒惰地。
惰性 性质是延迟执行的结果,这可能是您看到它在下一个周期触发的原因。
watchEffect
Runs a function immediately while reactively tracking its dependencies and re-runs it whenever the dependencies are changed.
watch
Compared to watchEffect, watch allows us to:
- Perform the side effect lazily;
- Be more specific about what state should trigger the watcher to re-run;
- Access both the previous and current value of the watched state.
找到了解决方案,watchEffect 不是办法。
看起来是同一个滴答中的多个更新事件的问题,对我来说,使用 { flush: 'post' }
作为手表功能的选项来处理手表的刷新。
我正在使用这个反应对象构建一个复杂的表单
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 函数内部发出的事件被一个渲染延迟了....
尝试在组件中使用key:prop。我认为它会解决问题。
TL;DR;
使用watchEffect
代替watch
...请注意,我没有尝试重现,我的猜测是您 运行 遇到了这个问题,因为您使用的 watch
运行 懒惰地。
惰性 性质是延迟执行的结果,这可能是您看到它在下一个周期触发的原因。
watchEffect
Runs a function immediately while reactively tracking its dependencies and re-runs it whenever the dependencies are changed.
watch
Compared to watchEffect, watch allows us to:
- Perform the side effect lazily;
- Be more specific about what state should trigger the watcher to re-run;
- Access both the previous and current value of the watched state.
找到了解决方案,watchEffect 不是办法。
看起来是同一个滴答中的多个更新事件的问题,对我来说,使用 { flush: 'post' }
作为手表功能的选项来处理手表的刷新。