Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Prop in Vue component is not reactive

Either I have a basic misunderstanding of Vue.js or I have found a bug. I am able to reproduce this bug (?) in the minimal example below.

The component App.vue has a reactive message variable, which is passed down to the child Child.vue as a prop. This message can be changed with a button. This works fine. However, when you alert the message in the Child, you will always get the first message – it is not updated at all. It seems that the message is only updated in the markup, not in the JavaScript. I am really confused by this behavior.

App.vue

<script setup>
import { ref, computed } from "vue";
import Child from "./components/Child.vue";

let index = ref(0);
let messages = ["hi", "there", "this", "is", "strange"];

let message = computed(() => messages[index.value]);

function change_message() {
    index.value++;
    if (index.value === messages.length) {
        index.value = 0;
    }
}
</script>

<template>
    <Child :message="message"></Child>
    <div>
        <button @click="change_message">Change message</button>
    </div>
</template>

Child.vue

<script setup>
const { message } = defineProps(["message"]);
function alert_message() {
    window.alert(message);
}
</script>

<template>
    <h1>
        {{ message }}
    </h1>
    <button @click="alert_message">Alert message</button>
</template>

Demo

demo of the bug

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

There is a workaround: Do not destructure the props in the Child. So write const props = defineProps(["message"]); and then use window.alert(props.message);. However, in a real-world Vue application, this will result in quite bloated code. I do not want to carry the props. around all the time.

>Solution :

When you destructure the props, you are loosing reactivity, For your case one way could be use toRefs:

Child.vue

<script setup>
import { toRefs } from "vue";

const props = defineProps(["message"]);
const { message } = toRefs(props);

function alert_message() {
  window.alert(message.value);
}
</script>


<template>
  <h1>
    {{ message }}
  </h1>
  <button @click="alert_message()">Alert message</button>
</template>

https://codesandbox.io/s/nameless-water-jwhw90?file=/src/components/Child.vue

Anyway is an standard to use props.<your_prop> when it’s required, even for in a real-world Vue apps

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading