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

dperrymorrow

David Morrow

Posted on May 24, 2024

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

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

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

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

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!

💖 💪 🙅 🚩
dperrymorrow
David Morrow

Posted on May 24, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related