It's easy in Vue to provide/give props or properties to a child element. Properties in Vue are one of the main ways we can pass data from a parent element or vue template to a child element. For example, in the code below, we give our child element PopularList
the property name
, and set it to Most Popular Posts
. That means that PopularList
can now access the data Most Popular Posts
:
<PopularList name="Most Popular Posts" />
However, sometimes child elements can contain other child elements. If we want to pass data from a parent component to a grandchild component, an easier way of doing this is with provide/inject. This lets us provide data at a parent level, and inject it at any level below that.
This means if we have a property that is not used by the child, but is used by the grandchild, we don't have to unnecessarily pass it through both, like Parent → Child → GrandChild
- we can instead simply pass it as Parent → Grandchild
, as shown in the diagram below:
If you are using the composition API, you can provide
any set of data using the provide
function:
<script setup>
import { provide } from 'vue'
provide('myKey', 'message');
</script>
provide
has both a key, and a value - above, the key is myKey
, and the value is message
. As with props, this could be an object, a number, or any other valid type. We can also make this property reactive, so it stays up to date in the grandchild element by using the ref
function:
<script setup>
import { provide, ref } from 'vue'
const message = ref('message');
provide('myKey', message);
</script>
If you are using the Options API instead, you can provide data in a component using the following structure:
export default {
provide: {
myKey: 'message'
}
}
If you want the Options API version of reactivity in provide
, you have to use computed
. As such, the composition API is a little more straightforward to use with provide/inject
. We also need to use the provide()
notation if we are giving any per-instance state - i.e. where the data is coming from the data()
.functio.
export default {
data() {
return {
message: 'message'
}
},
provide() {
return {
// This sets `myKey` to the message property from data().
// Putting it in `computed()` makes it reactive.
myKey: computed(() => this.message)
}
}
}
Now that we've provided data, it can be accessed in any child component at any level by using the inject
function.
Now that we've defiend provide
in a component, you can access that data using inject
. In a child component or a grandchild component, we can access myKey
to refer to message
. For example, suppose we have a Vue component that looks like this:
<script setup>
import { ref, provide } from 'vue'
import ChildElement from './Child.vue';
const message = ref('message');
provide('myKey', message);
</script>
<template>
<p>Hello World!</p>
<ChildElement />
</template>
... And then a child element (Child.vue
) that looks like this:
<script setup>
import GrandChildElement from './GrandChildElement.vue';
</script>
<template>
<GrandChildElement />
</template>
Within GrandChildElement
, we can access myKey
, since we provided it in a parent. We could also do this in Child.vue
, but we could also just use props for that. provide
gives us the power to get data from multiple levels up. To access this data in GrandChildElement
, we use inject
. Our GrandChildElement.vue
file could look a little like this:
<script setup>
import { inject } from 'vue'
const message = inject('myKey')
</script>
const message
here will return the text message
, since that's what we set myKey
to with provide
. If you're using the Options API, you can do this instead:
export default {
inject: [ 'myKey' ],
created() {
// Can access this.myKey here
}
}
Now the value of myKey
is available to a grandchild component, without the need to pass it to the child first via props.
Also published here.