Vue3 中关于 defineProps 的一些 “糖”

const { foo, bar } = defineProps(['foo', 'bar'])

在思否刷到一个问题 🔗 Vue3: 响应式 props 解构得到的变量将不是响应式?也不会更新? 按照问题中引用的文档描述来说确实是不能够解构返回值的。但是问题主提供的两个例子又说明了实际情况下,defineProps() 的返回值是能够被解构的。

VueJS 的 <script setup> 文档 中关于 defineProps() 的部分也没有针对其返回值是否能够解构做出说明。
我在Vue3项目的开发过程中并没有考虑到过这个问题,一直都是通过 props.xx 的形式来使用的。一下子就命中了我的知识盲区,还是 Vue3 写的少了啊。

不过在问题主引用的文档开头有一个响应性语法糖被 移除 的提示,所以去看了一下提示中链接的 废弃原因

在此RFC的 Unresolved Questions - defineProps destructure details 部分中提到了 non-reactive 的例子:

const props = defineProps(['foo', 'bar'])
const { foo } = props // non-reactive
props.bar // reactive access to `bar`

所以其实问题主的解构方式命中了正确的响应性语法糖书写方式,所以解构出来的变量是响应式的。

😥 但是文档和RFC中不是说已经被 “移除” 了吗,为什么还能继续使用?

确实,文档和RFC中都已经明确的说明 响应性语法糖 这个方案被放弃了。但是不是完全放弃了整个提议 响应式 props 解构 部分被保留了下来。这个可以从相关的另外一个RFC中看到 👉 prop sugar · vuejs/rfcs · Discussion #394,并且在 v3.2.20 中被合并。也可以在 Announcing Vue 3.3 | The Vue Point 中看到。

且不再是 ref: propsName 这样的写法,而是和文章开头提到的如使用原生解构语法一致的:

const {
  foo,
  bar = 123, // default value
  baz: qux = 234, // aliasing + default value
  ...rest // rest spread also supported
} = defineProps<{ foo: string, bar?: number, baz?: number }>()

watchEffect(() => {
  console.log(foo) // will log every time foo changes
})

🔨 defineProps

我们在有 Vue2 开发经验的情况下编写 Vue3 的项目时,一般情况下上手就会使用 <script setup> 来开发(美名其曰Vue3怎么能不体验 script:setup 😂),并且经常会跳着阅读文档。

所以可能会遗漏如何在 defineProps 宏中进行额外校验的阅读。并且在文档的 <script setup> 部分中缺少了关于 defineProps 使用的详细说明。只简单说明了TS项目中的如何进行类型声明和搭配 withDefaults 的使用设置默认值 👇

export interface Props {
  msg?: string
  labels?: string[]
}

const props = withDefaults(defineProps<Props>(), {
  msg: 'hello',
  labels: () => ['one', 'two']
})

那么就会不知道如何对 props 属性设置必填校验 required 和默认值 default。其实这部分的内容在文档的 Props 部分中已经详细说明了 👉 #Prop 校验 - Props | Vue.js


相关资源

vue3 - Vue3: 响应式 props 解构得到的变量将不是响应式?也不会更新? - SegmentFault 思否
响应性语法糖 | Vue.js

[⚠️ Dropped] Reactivity Transform · vuejs/rfcs · Discussion #369
prop sugar · vuejs/rfcs · Discussion #394
core/changelogs/CHANGELOG-3.2.md at main · vuejs/core

Vue: What to Expect in 2023 by Evan You - Vue.js Nation 2023
Announcing Vue 3.3 | The Vue Point

Props | Vue.js