How Provide and Inject work in Vue

Johnny Simpson - Jul 31 '22 - - Dev Community

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" />
Enter fullscreen mode Exit fullscreen mode

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 which 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>
Enter fullscreen mode Exit fullscreen mode

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, or 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>
Enter fullscreen mode Exit fullscreen mode

If you are using the Options API instead, you can provide data in a component using the following structure:

export default {
    provide: {
        myKey: 'message'
    }
}
Enter fullscreen mode Exit fullscreen mode

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() function.

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)
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

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 which 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>
Enter fullscreen mode Exit fullscreen mode

... And then a child element (Child.vue) that looks like this:

<script setup>
    import GrandChildElement from './GrandChildElement.vue';
</script>
<template>
    <GrandChildElement />
</template>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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
    }
}
Enter fullscreen mode Exit fullscreen mode

Now the value of myKey is available to a grandchild component, without the need to pass it to the child first via props.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .