Vue 3 中 props 不能直接解构,否则丢失响应式;应使用 toRefs、defineModel 或 toRef 安全解构:toRefs 适用于全部字段,defineModel 简化 v-model 场景,toRef 更轻量且类型友好。

Vue 3 中的 Props 不能直接用 ES6 解构语法自动解构,因为这会破坏响应式连接。但有几种安全高效的方式实现类似效果,既保持响应性,又减少 .value 的重复书写。
用 toRefs 保留响应式解构
当父组件传入的是响应式对象(如 ref 或 reactive),子组件 props 是只读的响应式代理。直接解构会丢失响应性,但 toRefs 可以把 props 中的每个字段转为独立的 ref,且保持与源 props 的响应式链接:
import { toRefs } from 'vue'
const props = defineProps({
title: String,
count: Number,
isActive: Boolean
})
// 安全解构:每个都是 ref,可直接在模板中使用
const { title, count, isActive } = toRefs(props)
这样在模板里就能写 {{ title }}、{{ count }},无需 {{ props.title }},也无需 {{ title.value }}(toRefs 返回的是 ref,但模板中自动解包)。
用 defineModel 简化双向绑定(v-model)场景
如果 props 主要用于 v-model(比如表单组件),Vue 3.4+ 支持 defineModel,它本质是语法糖,自动生成带 setter 的 ref,省去手动声明和 emit:
立即学习“前端免费学习笔记(深入)”;
审查 Vue 管理后台的变更请求(Vue 2 + Element UI,Vue 3 + Element Plus)。重点关注最小化变更实现、上线风险检查以及回归检查清单生成。
// 子组件(支持 v-model)
const model = defineModel()
// 等价于:
// const props = defineProps(['modelValue'])
// const emit = defineEmits(['update:modelValue'])
// const model = computed({
// get() { return props.modelValue },
// set(v) { emit('update:modelValue', v) }
// })
搭配 toRef 或 toRefs 还能进一步解构多个 v-model:
const title = defineModel('title')
const content = defineModel('content')
用 computed + toRef 按需解构(推荐用于非必需字段)
如果只对部分 props 做“解构式访问”,且希望保持简洁和类型友好,可用 toRef 单独提取:
-
toRef(props, 'title')→ 得到一个只读 ref,模板中直接{{ title }} - 比
toRefs更轻量,避免解构所有字段 - TypeScript 类型推导更准确(不会丢失联合类型信息)
import { toRef } from 'vue'
const props = defineProps<{ title?: string; size?: 'sm' | 'lg' }>()
const title = toRef(props, 'title')
const size = toRef(props, 'size')
不推荐:直接解构 props 对象
以下写法看似简洁,但会丢失响应性,导致模板无法更新:
// ❌ 错误!脱离响应式系统
const { title, count } = defineProps({ title: String, count: Number })
因为 props 是一个响应式代理对象,直接解构得到的是普通 JS 值(或原始值拷贝),后续 prop 更新时,这些变量不会同步变化。

















