Tham
Tham XYZ

Tham XYZ

Vue3 state management with provide, inject and reactive

NOT a replacement for Vuex

Vue3 state management with provide, inject and reactive
Tham's photo
Tham

Published on Jun 29, 2021

3 min read

Subscribe to my newsletter and never miss my upcoming articles

State management is one of key feature for any web application. When we develop multi component application, managing state across different component would be challenging. Every popular web frameworks like Angular , React and Vue has their own state management modules or patterns. In this article I am going to cover how the state management can be done with Vue framework

Vuex

Vuex is the answer for managing state till vue2. This enforces certain principles to manage or share the state across components. This also brought some challenges when we develop a small / medium sized applications. This is when vue3's provide and inject pattern offers a clean and simple approach to manage states.

Provide / Inject pattern

As the name suggests provide is for exposing objects to its child components. Inject is for injecting the objects in the child components. You might think that, we can also pass values from parent to child components. Why we need a new approach to solve the same problem. The real benefit of provide / inject approach is that, you can inject or use the exposed values from any child components. You don't require to pass the values all the way down from each child components in the tree.

Reactivity

On top of provide / inject pattern we can also mix the Vue3 reactivity feature to achieve the real state exchange between components. Let me explain this with some simple code.

//store.js
// Simple store file to expose the state
import { reactive, readonly } from "vue";

//This is the reactive state
const state = reactive({
  count: 0
});

//function to mutate any value in the state
const increment = () => {
  state.count++;
  console.log(state.count);
}

//expose the state in a readonly state to avoid direct mutation
export default {
  state: readonly(state),
  increment
};
// App.vue
<template>
  <h1>{{ msg }}</h1>
  <Child />
  <hr>
  <div>
    Child component: {{ store.state.count }}
    <p>
      <button @click="store.increment()">
        +1
      </button>
    </p>
  </div>
</template>

<script>
  import { provide } from 'vue';
  import store from './store.js';
  import Child from './Child.vue';

  export default {
    components: {
      Child
    },
    setup() {
      const msg = 'Provide + Inject + Reactive Example'
      provide('STORE', store)
      return {
        msg,
        store,
      }
    }
  }
</script>

notice the provide function which exposes the store

//Child.vue
<template>
  <div>
    Child component: {{ value }}
    <p>
      <button @click="plusOne">
        +1
      </button>
    </p>
  </div>
</template>

<script>
  import { inject, toRef, computed } from 'vue';
  export default {
    setup() {
      const store = inject('STORE');
      const value = toRef(store.state, 'count');
      const plusOne = () => {
        store.increment();
      };
      return {
        value,
        plusOne
      }
    }
  }
</script>

notice the inject function which inject the store into the child component.

// Replace toRef with the below will also produce the same result
const value = computed(() => store.state.count );

This way we can easily pass on any state object and inject at any child components. This is giving lots of flexibility to the developers to manage the state in a better way.

This is not about replacing the usage of Vuex. Vuex is still a great plugin for state management for larger applications. Vuex also provides lots of tooling support and debugging capabilities. This is your choice to decide which one to use based on your business requirement.

 
Share this