Vue3组件onMounted钩子未触发问题(TS+组合式API)
问题
项目基于Vue3 + Typescript + 组合式API开发,现有一个子组件,内部使用onMounted钩子在数据变更后设置相关属性。父组件通过API请求获取新数据后,将数据通过props传递给子组件,预期子组件会再次触发onMounted钩子完成属性设置,但实际并未生效。
子组件代码如下:
<script lang="ts" setup> import Iconbase from '@/components/icons/Iconbase.vue' import { ref, onMounted } from 'vue' interface Option { title: string value: number } const emits = defineEmits(['selected']) const open = ref(false) const defaultValue = ref<Option>() const props = defineProps({ status: { type: Number, required: true }, options: { type: Array as () => Option[], required: true }, selectable: { type: Boolean, require: true } }) function openSelect() { if (props.selectable) { open.value = !open.value } } function setActiveValue(item: Option) { defaultValue.value = item emits('selected', item.value) } onMounted(() => { defaultValue.value = props.options.find((option: Option) => { console.log('DisplayStatus.onMounted()'); if (option.value === props.status) return option }) }) </script>
解决方案
核心原因
onMounted是Vue的生命周期钩子,仅在组件首次挂载到DOM时执行一次,后续父组件更新props传递新数据时,不会再次触发该钩子,这是Vue生命周期的既定规则。
可行解决方式
方式1:监听props变化触发同步逻辑
将设置defaultValue的逻辑抽成独立函数,在组件挂载时执行一次,同时监听status和options的变化,自动触发同步:
<script lang="ts" setup> import Iconbase from '@/components/icons/Iconbase.vue' import { ref, onMounted, watch } from 'vue' interface Option { title: string value: number } const emits = defineEmits(['selected']) const open = ref(false) const defaultValue = ref<Option>() const props = defineProps({ status: { type: Number, required: true }, options: { type: Array as () => Option[], required: true }, selectable: { type: Boolean, require: true } }) function openSelect() { if (props.selectable) { open.value = !open.value } } function setActiveValue(item: Option) { defaultValue.value = item emits('selected', item.value) } // 抽离同步逻辑 const syncDefaultValue = () => { defaultValue.value = props.options.find(option => option.value === props.status) } onMounted(syncDefaultValue) // 监听关联props的变化 watch([() => props.status, () => props.options], syncDefaultValue, { deep: true // 数组是引用类型,需要深度监听内部元素变化 }) </script>
方式2:使用计算属性自动响应变化
如果defaultValue仅由props的status和options决定,不需要手动修改,直接用计算属性替代ref,它会自动响应props变化:
<script lang="ts" setup> import Iconbase from '@/components/icons/Iconbase.vue' import { ref, computed } from 'vue' interface Option { title: string value: number } const emits = defineEmits(['selected']) const open = ref(false) const props = defineProps({ status: { type: Number, required: true }, options: { type: Array as () => Option[], required: true }, selectable: { type: Boolean, require: true } }) function openSelect() { if (props.selectable) { open.value = !open.value } } function setActiveValue(item: Option) { // 若使用计算属性,这里需要调整逻辑:直接触发emit,由父组件更新props.status emits('selected', item.value) } // 用计算属性替代原有的defaultValue ref const defaultValue = computed(() => { return props.options.find(option => option.value === props.status) }) </script>
注意:如果需要允许用户手动修改
defaultValue(不依赖props),优先选择方式1;如果defaultValue完全由props驱动,方式2更简洁高效。
内容的提问来源于stack exchange,提问作者Čamo
相关产品推荐
相关产品推荐

