How to avoid and fix prop drilling in Vue.js
I've been using Vue.js for a while now but there are still some patterns and things I discover. Recently I did a course at Vueschool.io on the topic of common mistakes in Vue.js and how to fix them. One concept they explained was Prop drilling.
In this blog I'll show you what prop drilling is and how to fix it.
What is prop drilling?
Say you have a several components which are nested: You have an App
which has a ChildComponent
and a GrandComponent
.
App
--ChildComponent
----GrandChildComponent
If you want to use a variable from the App
in GrandChildComponent
, you need to pass down a prop to the ChildComponent
which in turn passes it down to the GrandChildComponent
it gets messy pretty quickly, especially if it is even further down the hierarchy. You might forget to pass the prop or you accidentally modify the prop as you pass it along.
So how do we fix this?
Provide/inject
One solution is to use provide/inject into your components.
Example
in App.vue
you do the following:
<script setup>
import { provide, ref } from 'vue'
const currentWriter = ref({
name: 'John Doe',
storyCount: 5,
});
provide('currentWriter', currentWriter);
</script>
In GrandChildComponent.vue
<script setup>
import { inject } from 'vue'
const currentWriter = inject('currentWriter');
</script>
Easy! 👍
You can also add a function that modifies the value that is being passed down. It is recommended to keep the function inside of the 'Provider'. This makes it easier to maintain because it keeps the logic in 1 place.
<script setup>
import { provide, ref } from 'vue'
const currentWriter = ref({
name: 'John Doe',
storyCount: 5,
});
function addStory() {
currentWriter.value.storyCount++;
}
provide('currentWriter', {
currentWriter,
addStory
});
</script>
In GrandChildComponent.vue
<script setup>
import { inject } from 'vue'
const {currentWriter, addStory} = inject('currentWriter');
</script>
<template>
{{ currentWriter.storyCount }}
<button @click="addStory">Add story</button>
</template>
It's quite easy to use and keeps the code clean. If you'd like to know more, you can view the the VueJS documentation. There are some other approaches to fix this issue like Composables or state management. You can check out the documentation which provides some very clear examples!