Reputation: 15220
This is the setup:
Parent component: Has a reactive Todo object with a checked state {checked: true
and passes it to a Todo
component.
Todo component: Accepts the Todo as a prop and binds the checked
value to a checkbox. Upon toggling the checkbox, it emits an event to the parent, which then asynchronously updates the checked
state of the Todo.
Parent:
<template>
<Todo @update="handleUpdate" :todo="todo" />
</template>
<script setup>
import { reactive } from "vue";
import Todo from "./components/Todo.vue";
let todo = reactive({ checked: true });
let handleUpdate = (e) => {
setTimeout(() => {
// Always sets it to false for test purposes
todo.checked = false;
}, 1000);
};
</script>
Child:
<template>
<input type="checkbox" v-model="checkboxProxy" />
</template>
<script setup>
const { computed, defineProps, defineEmits } = require("vue");
let props = defineProps(["todo"]);
let emit = defineEmits(["update"]);
let checkboxProxy = computed({
get() {
return props.todo.checked;
},
set(val) {
emit("update", val);
},
});
</script>
Question: I would expect the checkbox to get unchecked a second after it has been checked. But that doesn't happen. Why?
Codesandbox: https://codesandbox.io/s/crazy-snow-kdse27
I also tried this setup:
<input type="checkbox" :checked="todo.checked" @change="emit('update)" />
But it still not reflecting the todo state. I'm testing in Brave it that matters.
Upvotes: 0
Views: 1875
Reputation: 344
You are not changing the todo
object itself but just the HTML element. Meaning, once the state is set to false it is not updated to true when you emit the event.
And because you use reactive and computed the state is cached, so nothing will happen until something is changed.
let handleUpdate = (e) => {
// actually changing the state here
todo.checked = true;
setTimeout(() => {
// Always sets it to false for test purposes
todo.checked = false;
}, 1000);
};
todo.checked = true
is going to change the state and after one second (in your case) it is going to be set back to false, which respectively will update the props and the checkbox itself.
Updated:
To update the checkbox based on the response you can either:
Todo.vue
<div>
<input type="checkbox" :checked="props.todo.checked" @click.prevent="emit('update', $event.target.value)" />
<div>Prop value: {{ todo }}</div>
</div>
If I'm not mistaken, using Vue.set()
in vue 2 actually will result in the same (visual) behavior as pt2
Keep in mind that both ways are not very UX-friendly.
Upvotes: 1