Vue中如何从嵌套props解包数据?解包后变量失响应性怎么办?
Vue嵌套Props解包与响应性问题解答
问题1:如何从嵌套props中解包数据?
问题2:为何从props解包后的变量会失去响应性?
场景说明
我有三个组件:父组件、用于展示的ChildA组件、用于根据输入更新数据的ChildB组件(代码已大幅简化)。ChildB组件通过事件更新父组件数据,更新后的值需传递给ChildA组件。我知晓该架构可能存在问题,且未使用状态管理库。预期效果是emit更新值后,ChildA组件能显示新值,但仅在不解包props时生效。
代码示例
Parent.vue
<template> <ChildA :data="data"/> <ChildB @update-data="updateData"/> </template> <script setup> import { reactive, toRefs } from "vue"; const { data } = toRefs( reactive({ data: { latestEvent: { status: "fail" } } }) ); const updateData = (event) => { data.value = event; }; </script>
ChildA.vue
<template> {{ latestStatus }} </template> <script setup> import { computed, toRefs } from "vue"; const props = defineProps({ data: { type: Object, default: () => {}, }, }); const { data } = toRefs(props); const { latestEvent } = data.value; const latestStatus = computed(() => data.value.latestEvent.status); // const latestStatus = computed(() => latestEvent.status); THAT'S NOT REACTIVE </script>
ChildB.vue
<template> <select v-model="status" @change="onChange()"> <option value="in progress">in progress</option> <option value="new">new</option> <option value="fail">fail</option> </select> </template> <script setup> import { reactive, ref, toRefs } from "vue"; const status = ref(""); const emit = defineEmits(["updateData"]); const onChange = () => { emit( "updateData", toRefs( reactive({ latestEvent: { status: status }, }) ) ); }; </script>
问题解答
为何解包后变量失去响应性?
你执行const { latestEvent } = data.value;时,只是把data.value当前的latestEvent属性值(普通对象)赋值给了变量latestEvent,这个赋值是一次性的。后续data.value更新时,latestEvent不会自动同步新的对象,因此用它创建的计算属性无法感知数据变化,自然失去响应性。Vue的响应性依赖于对响应式对象属性的访问,直接解构普通对象会断开这种依赖关系。
如何让解包后的变量保持响应性?
你设想的写法有误,因为data是Ref对象,不是响应式对象,正确的做法是对data.value(响应式对象)进行解构,或者用toRef单独获取嵌套属性的Ref,以下是几种可行方案:
方案1:用toRefs解构响应式对象
const { data } = toRefs(props); // data.value是响应式对象,解构后得到的latestEvent是Ref const { latestEvent } = toRefs(data.value); const latestStatus = computed(() => latestEvent.value.status);
方案2:用toRef单独获取嵌套属性
const { data } = toRefs(props); // 直接为data.value的latestEvent属性创建Ref const latestEvent = toRef(data.value, 'latestEvent'); const latestStatus = computed(() => latestEvent.value.status);
方案3:直接在计算属性中访问嵌套属性(最简单)
无需提前解构,直接在computed中访问响应式对象的嵌套属性,这种方式能天然保持响应性:
const { data } = toRefs(props); const latestStatus = computed(() => data.value.latestEvent.status);
额外修正:ChildB组件的错误
你在ChildB中emit时传递的是toRefs(reactive(...)),这会把一组Ref对象传给父组件,而父组件的data.value期望的是普通对象。应修改为直接传递普通对象,同时注意访问Ref的value属性:
const onChange = () => { emit( "updateData", { latestEvent: { status: status.value }, } ); };
内容的提问来源于stack exchange,提问作者user3648963
相关产品推荐
相关产品推荐

