Why my variables after unwrapping from props stops being reactive?
I three components - parent, second for displaying and third for updating data depending on input (code is very simplified here).
Third component is updating parent via event and that updated value should be passed to child. I know that architecture might smell. I'm not using any store.
What I would expect is that emit is updating value and on Child1
new value is displayed. That happen if I do not unwrap unwrapped prop.
// 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>
How to make my variables reactive after unwrapping from prop?
I would imagine something like this:
const { data } = toRefs(props);
const { latestEvent } = toRefs(data);
CodePudding user response:
Since the whole data
and not just data.latestEvent.status
value is changed, destructuring it early like const { latestEvent } = data.value
disables the reactivity. latestEvent
refers data.latestEvent
object that exists at the time when setup function runs.
What happens here is basically:
let foo = { bar: { baz: 1 } };
let bar = foo.bar;
let baz = foo.bar.baz;
foo.bar = { baz: 2 };
console.log(bar !== foo.bar); // true
console.log(baz === 1); // true
It should always be:
const latestStatus = computed(() => data.value.latestEvent.status);