Vue Tip: Mutate Your State Inside of the Provider Using Provide and Inject
Michael Hoffmann
@mokkapps

Provide / Inject is a powerful feature in Vue that allows you to pass data down to all of your child components without having to pass it down through props. This is especially useful when you have deeply nested components that need access to the same data.
In this article, I'll show you the recommended way to mutate your state inside of the provider using provide
and inject
.
The Problem
Let's say you have a Provider.vue
component that uses provide
and inject
to pass down the count state to all of its child components:
<script setup>
import { provide, ref } from 'vue'
const count = ref(0)
provide('provide-data', {
count
})
</script>
Let's take a look at a child component that uses inject
to access & mutate the provided count state:
<script setup>
import { inject } from 'vue'
const { count } = inject('provide-data')
</script>
<template>
<div>
<span>Count: {{ count }}</span>
<button @click="count++">Increment</button>
</div>
</template>
This works great, and the child component can access the count state and increment it when the button is clicked. This works because count
is injected via ref
and thus can be mutated by every component that injects it.
For better maintainability, you should move the increment logic into the provider component and provide count
as read-only to the child components.
The Solution
To achieve this, you can create a method in the provider component that increments the count state and provide this method to the child components:
<script setup>
import { provide, ref, readonly } from 'vue'
const count = ref(0)
const incrementCount = () => {
count.value++
}
provide('provide-data', {
count: readonly(count),
incrementCount
})
</script>
<script setup>
import { inject } from 'vue'
const { count, incrementCount } = inject('provide-data')
</script>
<template>
<div>
<span>Count: {{ count }}</span>
<button @click="incrementCount">Increment</button>
</div>
</template>
Now, the child component can access the count state as a read-only value and call the incrementCount
method to increment the count state. This allows you to encapsulate the logic for mutating the state inside of the provider component and provide a clean interface to the child components.
provide
and inject
.StackBlitz
Try it yourself in the following StackBlitz:
If you liked this Vue tip, follow me on BlueSky to get notified about new tips, blog posts, and more. Alternatively (or additionally), you can subscribe to my weekly Vue & Nuxt newsletter :