paint-brush
Using Provide and Inject in Vueby@smpnjn
249 reads

Using Provide and Inject in Vue

by Johnny SimpsonAugust 1st, 2022
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

It's easy in Vue to provide/give props or properties to a child element. If we want to pass data from a parent component to a grandchild, 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. For example, we give our child element `PopularList` the property `name` and set it to `Most Popular Posts`. We can also make this property reactive, so it stays up to date in the grandchild element.
featured image - Using Provide and Inject in Vue
Johnny Simpson HackerNoon profile picture


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:


Provide and Inject Diagram

How to use provide and inject in Vue

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.

Accessing parent data using inject in Vue

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.