May 24You don't need Vuex / Pinia for shared state in Vue.

You don't need Vuex / Pinia for shared state in Vue.

Since Vue.js 3.x, you no longer need to use Vuex to share a centralized state with all your application's components.

A brief history of shared state in Vue.js

If you have been using Vue.js before 3.x you are probably familiar with Vuex now renamed Pinia. It allows you to have a centralized state that is shared across all your application components. If you have ever found yourself in situations where you are passing data/props between components and things are getting complicated, a centralized state is the answer.

Flux libraries are like glasses: you’ll know when you need them.

The simplest way to share the state between components.

Since Vue.js 3.x reactive and computed are exported directly from the library and can be used outside of components. This is the exact same functionality that you are using when you have data or computed inside of one of your Vue.js components.

import { reactive, computed } from 'vue';

This is great because it means that we can create our own reactive data, and even computed properties outside of Vue components, in plain Javascript files!

Example of shared state

import { reactive, computed } from "vue";

const state = reactive({
  hobby: "Hike",
  fruit: "Apple",
  fruitOptions: ["Banana", "Apple", "Pear", "Watermelon"],

  description: computed(() => {
    return `I like eating ${state.fruit}s & ${state.hobby}`;
  }),
});

export default state;

Here we have an Object with properties, which is wrapped in reactive this gives Vue the ability to trigger change, and re-render your components.

Computed

We are also wrapping a function in computed which gives us a computed property based on the the other fields in the state.

It is important to note, that we invoke the reactive function, and THEN export the resulting state, otherwise we would create a new state each time we imported the file.

Usage in your components

Great, we have a reactive store, but how do we leverage this in our components, and will they all stay in sync?

<template>
  <main class="container">
    <article>
      <header>
        Your description: <code>{{ state.description }}</code>
      </header>
      <survey-form />
      <footer>
        <results />
      </footer>
    </article>
  </main>
</template>

<script>
import Results from "./Results.vue";
import SurveyForm from "./SurveyForm.vue";
import state from "./state.js";

export default {
  components: { SurveyForm, Results },
  data() {
    return { state };
  },
};
</script>

It's as simple as importing the state, and referencing it in your component's data method so it can be accessed in your template.

You can even v-model items in your store the same as you would with any data property in your component.

<template>
  <form>
    <label>
      Favorite Hobby?
      <input placeholder="Favorite Hobby" v-model="state.hobby" />
    </label>

    <label>
      Favorite Fruit?
      <select v-model="state.fruit">
        <option v-for="fruit in state.fruitOptions" :key="fruit">{{ fruit }}</option>
      </select>
    </label>
  </form>
</template>

<script>
import state from "./state.js";

export default {
  name: "SurveyForm",
  data() {
    return { state };
  },
};
</script>

You can see the full example on Github and view the code here

I hope you find this pattern as useful as I have. Happy developing!

Comments

  • samthatcode

    This is interesting. Does this work in larger projects like for example an admin based project ie role based access control kind of project, crud applications

    • dperrymorrow

      It would scale as well as reactive data in a component does, as its the same logic being used in both places. The main advantage of a flux lib like Vuex IMO is that you can organize logic in different modules. I suppose you could do something similar with this pattern, but it could get messy if you were not careful.

      • samthatcode

        Oh thanks. The link was helpful. I will be working on an admin based crud application with Casl package for ability -based among other things. Appreciate your feedback and response 🙏

    • patrickmonteiro

      Very good, since the release of vue 3 I have never needed vuex/pinia in my projects.