You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 19:01:08