Destructuring objects is a common practice in JavaScript, and it can make your code cleaner by extracting specific properties. In Vue.js, however, destructuring props can unintentionally break reactivity.
The Pitfalls of Destructured Props
⚡ You cannot destructure defineProps because the resulting destructured variables are not reactive and will not update. Read more
When you destructure props in Vue.js, the resulting variables become plain JavaScript objects. These objects are not reactive, meaning changes to the original props won't trigger a re-render in your component. This can lead to stale data being displayed.
For example, imagine a component displaying a firstName
and a lastName
based on a prop. If the prop is destructured, the properties won't update when the parent component changes the prop value.
<template>
<div>
<p>Name: {{ firstname }} {{ lastname }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue';
// ❌ Non-reactive props - this won't re-render
const { firstName, lastName } = defineProps({
firstName: String,
lastName: String,
});
</script>
Keeping destructured props reactive (if necessary)
If you still really, really want to destructure props, there are two ways to maintain reactivity:
- Reference your props object directly using
toRefs()
Vue’stoRefs
function takes a reactive object (like props) and returns a new object where each property is wrapped in aref
. Accessing properties using.value
(e.g.,prop1.value
) ensures reactivity.
⚡ Vue.js documentation advises against this approach for props, suggesting using the dot notation instead. Read more
<template>
<div>
<p>Name: {{ firstName }} {{ lastName }}</p>
</div>
</template>
<script setup>
import { ref, toRefs } from 'vue';
const props = defineProps({
firstName: String,
lastName: String,
})
const { firstName, lastName } = toRefs(props)
</script>
- Reference your props object directly using
computed()
:
<template>
<div>
<p>{{ fullName }}</p>
</div>
</template>
<script setup>
import { computed } from 'vue';
const { firstName, lastName } = defineProps({
firstName: String,
lastName: String
})
const fullName = computed(() => firstName + lastName)
</script>
The Bottom Line: Embrace the Dot Notation!
While destructuring can be useful for non-reactive objects, it’s generally recommended to access props directly using props.propertyName
in Vue.js.
<template>
<div>
<p>Name: {{ props.firstname }} {{ props.lastname }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue';
// ✅ Reactive props - this will re-render
const props = defineProps({
firstName: String,
lastName: String,
});
</script>
This approach guarantees reactivity and avoids potential issues.
Remember, young traveler, maintaining reactivity is crucial for dynamic Vue components. Choose the approach that suits your style, but be mindful of the potential pitfalls of destructuring props.
Top comments (10)
If you don’t use props in the script setup tag you can just “defineProps” without assigning a local variable “props” and they are available in the template. Are you saying this is implied destructuring? Becuase I’ve been doing this and I still have reactivity. 🤷♂️ Maybe I am mistaken.
Example:
You will still have reactivity if you define the props without assigning the definition to a variable you will be able to use the props
firstName
andlastName
in your example directly in the template and they will still be reactive.The downside of this approach is that it only works if you are creating a simple component and all of the props will be used in the
<template>
, if you want to use the props in some logic like function or computed ... etc you have to assign the props definition to a variableYes. That’s a good point! When I use the method I mentioned they are for base components and very simplex. I merely wanted to call out that it is possible to NOT assign props to a local variable to use in the template. If you need something more complex with props then your method along with computed values as above would be necessary.
For me I always go for assigning the props definition to a variable to set a standard for creating components with props in the project especially if there is a big team working on it.
Same here - much safer and less headache.
I actually wrote this article after reading a Tweet of a developer, who posted an example where he destructured props and runs into reactivity issues.
Not sure how that could cause headache 🤷 if you commit to only using that method in a BaseComponent type. You would NEVER use a based component directly as a rule; Only wrap a new component around that to encapsulate base functionality or style. It's a powerful technique for enterprise project that are VERY large and have many team members touching code. Once the base component is set according to the Design System spec you [in theory] never touch those classes directly. It's your core and all customization build on top where each team/dev that needs a specific "thing" wraps a base component to create what they need. Come time to Refactor only that teams component tree and views are risk factors for the change.
It's all preference. All methods are 'correct'. great post! 👍
I destructure variables in JS to improve performance, but at the very beginning (when I first started with Vue), I tried that with props and ran into the reactivity issues mentioned above. After some reading, I came to the conclusion that I should just go with dot notation. Also, I sometimes switch to computed functions with destructured props, just for overall readability, if I need an extra parse of the values. Long story short, I use two methods, depending on the use case.
Thank you - really appreciate your perspective on this.
Nope. That is not destructuring. Like @helwatany explains below - your example will still be reactive since you're not destructuring props.
@richardevcom Yes thank you. Than is my point exactly. You don't NEED to destructure IF you have a simple component, don't want to add extra memory allocation with a local 'prop' variable, and want to directly reference a prop value inside the tags. You can use the defineProps macro and just use the defined prop names in the template. They WILL be reactive.
True. Well, I prefer to use your example or dot notation and stay away from destructuring them (hence the article).