Props Are Read-Only
Props go one way: from the parent down to the component. The component reads them, but it mustn't change them. Let's say each item of the menu gets a button for a large cup, which costs €1 more:
<script setup>
const props = defineProps({
name: { type: String, required: true },
price: { type: Number, required: true },
});
function makeLarge() {
props.price = props.price + 1;
}
</script>
<template>
<li class="item">
<span>{{ name }}</span>
<span class="price">€{{ price }}</span>
<button @click="makeLarge">Large</button>
</li>
</template>defineProps returns the props in an object, here saved as props, for the script. (In the template, the price is still just price.) But a click on the button doesn't change the price, and the console says:
[Vue warn]: Set operation on key "price" failed: target is readonly.The props are read-only: they can be read, not changed. The price belongs to the parent, which can pass it to other components too. If each component could change it, different parts of the page would show different prices, and no one could tell which is right. (In the next lesson, you'll see how a component asks its parent to change the parent's data.)
Whether this one item is large is the business of the component, not of the parent. That's the component's own state: a ref in its <script setup>, as in App.vue:
const large = ref(false);And each <MenuItem /> gets its own. Every item on the page is a separate copy of the component with its own variables, so a large espresso doesn't make the tea large. The price the item shows can then be a computed value, made from the prop and the component's state.
Instructions
- 1
Click Large: the price stays, and the console shows the warning. Fix it: give
MenuItema reflarge,falseat first, whichmakeLargesets totrue. Show a computed valueshownPricein place ofprice: the price plus €1 when the item is large, and the price as it is otherwise. - 2
Let the customer change their mind: rename
makeLargetotoggleSize, which switcheslargefromfalsetotrueand back. When the item is large, the button saysRegularinstead ofLarge.