在 Vue 3 中,props
是响应式的对象。当我们在解构 props
属性时,本质上是创建了新的局部变量,这些变量不再和原始的响应式 props
对象绑定。显然,这些变量失去了原有的响应式,不能跟着 props
的变化而更新,自然拿不到最新的值。
举个例子👇:
父组件中定义:
const person = ref({ name: 'John', age: 30 });
// 引用子组件
<ChildComp :person="person" />
子组件中使用:
const {name, age} = defineProps({
person: Object,
});
看结果👇:
name
和 age
没变呢😫!因为结构使props中的属性拾取了响应式!!!
Vue 的响应式原理:
- Vue3 的响应式系统是基于 Proxy来实现的
- props 对象本身是一个响应式对象(Proxy 包装的)
当我们解构这个对象时,实际上是从这个 Proxy 对象中提取了普通的值:
// 这样写会失去响应性
const {name, age} = defineProps({
person: Object,
});
// 相当于:
const person = props.person // person 现在只是一个普通值的拷贝
举个🌰:
// 响应式对象
const state = reactive({ count: 0 })
// 解构后
const { count } = state
console.log(count) // 0
state.count = 1
console.log(count) // 仍然是 0,因为 count 只是一个普通的值
那怎么办呢🤷
解决方法
- 方法一:不结构,直接使用。
// 方法1:直接使用 props.person
const props = defineProps({ person: Object })
// 使用 props.person
- 方法二:使用 toRef 保持响应性。
toRef
将响应式对象的某个属性转换为一个独立的、响应式的 ref 对象。这样可以在保持响应性的同时单独使用某个属性。
// 方法2:使用 toRef 保持响应性
const props = defineProps({
person: Object,
});
const person = toRef(props, 'person');
- 方法三:使用 toRefs 保持响应性。
toRefs
将整个对象的每个属性都转换为 ref。
// 方法3:使用 toRefs 保持响应性
const props = defineProps({
person: Object,
});
const {name, age} = toRefs(props);
效果⬇️:
问题解决!