Optimizing Vue Performance with Prop Stability
In Vue.js, the component will re-render whenever a child component’s props change. This simple concept leads us to a crucial best practice that can s...
In Vue.js, the component will re-render whenever a child component’s props change. This simple concept leads us to a crucial best practice that can significantly enhance our app’s performance: prop stability.
What is Prop Stability?
Prop stability means keeping the props passed to a component stable, so they don't change frequently. This helps to avoid unnecessary re-renders and enhances your app's performance.
Example: List Item Component
Imagine we have a ListItem
component that receives id
, message
, and activeId
as props. Here’s how it might look in the template:
<template>
<div>
<span v-if="id === activeId">➤</span> {{ message }}
</div>
</template>
To help us see when the component updates, we can import onUpdated
from Vue and log a message whenever the component re-renders:
import { onUpdated } from 'vue';
export default {
props: {
id: Number,
message: String,
activeId: Number
},
setup(props) {
onUpdated(() => {
console.log(`Updating ${props.id}`);
});
}
}
Setting Up the Parent Component
In the parent component, we create an array of messages, each with a unique id
and message
, and a ref
to keep track of the active message:
import { ref } from 'vue';
import ListItem from './ListItem.vue';
export default {
components: { ListItem },
setup() {
const messages = [
{ id: 0, message: 'Message 1' },
{ id: 1, message: 'Message 2' },
{ id: 2, message: 'Message 3' },
];
const activeId = ref(0);
const next = () => {
activeId.value = (activeId.value + 1) % messages.length;
};
return { messages, activeId, next };
}
}
In the template, we render the ListItem
components and add a button to change the activeId
:
<template>
<ul>
<ListItem
v-for="item in messages"
:key="item.id"
:id="item.id"
:message="item.message"
:activeId="activeId"
/>
</ul>
<button @click="next">Next</button>
</template>
Identifying the Problem
When you click the button, you’ll notice that all ListItem
components re-render. This happens because the activeId
prop changes for every item, causing unnecessary re-renders.
Improving with Stable Props
To optimize this, we can change the ListItem
component to use an isActive
prop instead of activeId
:
<template>
<div>
<span v-if="isActive">➤</span> {{ message }}
</div>
</template>
In the parent component, we determine isActive
by checking if the id
matches activeId
:
<template>
<ul>
<ListItem
v-for="item in messages"
:key="item.id"
:id="item.id"
:message="item.message"
:isActive="item.id === activeId"
/>
</ul>
<button @click="next">Next</button>
</template>
With this change, only the active item and the previously active item re-render when activeId
changes. This reduces the number of re-renders, improving performance, especially for large lists.
I hope this will help, Happy Coding!