Javascript is required
ยท
2 min read

Vue Tip: Mutate Your State Inside of the Provider Using Provide and Inject

Vue Tip: Mutate Your State Inside of the Provider Using Provide and Inject Image

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:

Provider.vue
1<script setup>
2import { provide, ref } from 'vue'
3
4const count = ref(0)
5
6provide('provide-data', {
7  count
8})
9</script>

Let's take a look at a child component that uses inject to access & mutate the provided count state:

Child.vue
1<script setup>
2import { inject } from 'vue'
3
4const { count } = inject('provide-data')
5</script>
6
7<template>
8  <div>
9    <span>Count: {{ count }}</span>
10    <button @click="count++">Increment</button>
11  </div>
12</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:

Provider.vue
1<script setup>
2import { provide, ref, readonly } from 'vue'
3
4const count = ref(0)
5
6const incrementCount = () => {
7  count.value++
8}
9
10provide('provide-data', {
11  count: readonly(count),
12  incrementCount
13})
14</script>
Child.vue
1<script setup>
2import { inject } from 'vue'
3
4const { count, incrementCount } = inject('provide-data')
5</script>
6
7<template>
8  <div>
9    <span>Count: {{ count }}</span>
10    <button @click="incrementCount">Increment</button>
11  </div>
12</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.

Info

This approach is the official way to mutate the state inside of the provider using provide and inject.

StackBlitz

Try it yourself in the following StackBlitz: