I have a parent component Search that passes the prop query to a child component Results.
Search.vue
<template>
<div>
<input v-model="query" type="text" />
<Results :query="query" />
</div>
</template>
<script>
import { defineComponent } from "vue";
import Results from "./Results.vue";
export default defineComponent({
name: "Search",
components: { Results },
data() {
return {
query: "",
};
},
});
</script>
Results.vue
<template>
<div>{{ query }} ( {{ query.length }})</div>
</template>
<script setup>
import { defineProps, watch, computed } from "vue";
const { query } = defineProps({
query: {
type: String,
default: "",
},
});
const queryLength = computed(() => query.length);
watch(
() => query,
() => {
console.debug("Watcher was fired.");
}, {immediate: true}
);
watch(queryLength, () => {
console.debug("Watcher was fired.");
});
</script>
The watcher for the query prop never fires, except when I add {immediate: true} to the watcher, but then it does not fire on updates. It also doesn’t do anything when I add a computed property based on the query prop.
The strange thing is that when displaying the query prop, the value is rendered.
Here’s the simplest version of my code. What am I doing wrong?
>Solution :
You cannot destructure props directly as you do in
const { query } = defineProps({...})
or, to be precise, you can do it, but the resulting values won’t be reactive – query will be a simple string. So the value will be rendered, but watchers (among other things) will not work.
To avoid the error, either do not destructure at all or use the toRefs() utility function:
const props = defineProps({...})
const { query } = toRefs(props);
// or for a single prop:
const query = toRef(() => props.query)