I know this is an anti pattern, but it would simplify things a lot. And furthermore I’m just curious if it’s possible. When I call test1()
I get the following warning: Set operation on key "items" failed: target is readonly.
and nothing else happens. When I call test2()
items
change within the child AND the parent, BUT the computed setter ist not called. Why?
Why is the computed setter not called? Is it possible to mutate the props within the child and still have the computed setter called?
I’ve got the following parent component:
<template> <div class="m-10 bg-white"> parent: {{ items }} <br /> <br /> <TestComponent2 :items="items" /> </div> </template> <script lang="ts" setup> import { computed, ref } from "vue"; import TestComponent2 from "./TestComponent2.vue"; const container = ref({ items: ["a", "b", "c"], }); const items = computed({ get: () => { return container.value.items; }, set: (v) => { console.log("set", v); container.value.items = v; }, }); </script>
And this is the child component:
<template> <div> child: {{ items }} <br /> <br /> <button @click="test1()">test1</button> <br /> <button @click="test2()">test2</button> </div> </template> <script lang="ts" setup> import { defineProps, toRefs } from "vue"; const props = defineProps({ items: { type: Array, required: true, }, }); const { items } = toRefs(props); const test1 = () => { items.value = []; }; const test2 = () => { items.value.pop(); }; </script>
Advertisement
Answer
You’re likely looking for v-model:items="items"
.
The gist:
parent.vue:
<child v-model:items="items" />
child.vue:
emit('update:items', value);
Note: both items.pop()
and items.push()
will mutate the value in both parent and child, but they won’t trigger an assignment.
For that, you have to:
const copy = [...items]; copy.push('new'); // or pop(), splice()... // if inside child: emit('update:items', copy);
Docs here
Working example here
Technically,
<child v-model:items="items" />
is shorthand for:
<child :items="items" @update:items="value => items = value" />
In you don’t specify the child variable name (in our case items
), it defaults to modelValue
.