Connecting a shared store to multiple single file components in Vue.js 3 - here's how!

In my Vue.js 3 application, I have several single file components and I am looking for a simple way to manage global state. The documentation on state management is helpful, but it mainly focuses on using a reactive object returned from the data function within the same file. My challenge lies in implementing a shared store across multiple files.

  • app.vue
  • component-a.vue
  • component-b.vue
  • store.js

Let's take a look at these files:

app.vue

<template>
    <div>        
      <div>How much money do you have?</div>
      <input type="number" v-model="currentAmount" />
      <br />
      <div>How much money do you want?</div>
      <input type="number" v-model="desiredAmount" />
    </div>
</template>

<script>
  import ComponentA from './component-a.vue';
  import ComponentB from './component-b.vue';

  export default {
     components: {
       ComponentA,
       ComponentB
     },

     data() {
         return {
           currentAmount: 0,
           desiredAmount: 0
         }
     },
  }
</script>

component-a.vue

<template>
    <div>        
      <div>You have {{ remainingAmount }} to reach your goal.</div>
    </div>
</template>

<script>
  export default {
     data() {
         return {
           remainingAmount: 0
         }
     },
  }
</script>

component-b.vue

<template>
    <div>        
      <div>You are {{ progress }}% of the way there!</div>
      <button @click="increaseGoal">increase goal by $10</button>
    </div>
</template>

<script>
  export default {
     data() {
         return {
           progress: 0
         }
     },

     methods: {
        increaseGoal() {
           // need to increase targetAmount by $10
           store.targetAmount += 10; 
        }
     }
  }
</script>

store.js

import { reactive} from 'vue';

const store = reactive({
  startingAmount: 0,
  targetAmount: 0
});

Although the UI renders fine, the data is not being shared between the components. There seems to be a disconnect between the store and the three .vue files. I'm unsure how to properly link the store.js with the components.

If you have any insights on how to connect a shared store with multiple single file components without using Vuex, I would appreciate your guidance.

Answer №1

If you want to access the store globally in your VueApp, you can use the use() method to enable calling this.$store from any component.

main.js

import { createApp } from 'vue';
import store from './store/index'; // OR specify the path to your store
import router from './router/index';
import App from './App.vue';

createApp(App).use(router).use(store).mount('#app');

I have organized my store functionality into a separate folder for better modularization. The index.js file within the store folder holds the basic store setup and all modules.

store/index.js

import { createStore } from 'vuex';

const store = createStore({
  modules: {},
  state() {
    return {};
  },
  mutations: {},
  actions: {},
  getters: {},
});

export default store;

This approach allows you to easily access the store from any component.

component.vue

export default {
  name: 'users-list',
  created() {
    console.log(this.$store);
  },
}

It's important not to directly modify the variables in the store's state.

The store operates through 3 different types of procedures.

Actions - Perform Complex Operations


Actions handle complex data manipulation tasks and facilitate communication between different store modules. They are the only procedure group that has direct access to the store itself, with the first argument being the entire store object. You can trigger actions by using

dispatch('ModuleName/ActionName', Value)
.

Mutations - State Mutation Functions


Mutations are responsible for mutating the state, and it is essential to only use mutations for state changes to maintain reactivity and keep workflows clean. Mutations receive their local state as the first parameter and can be triggered by commit('MutationName', Value).

Getters - Retrieve States Easily


Getters are used to retrieve specific states from the store effortlessly.

Answer №2

If you prefer not to use Vuex for managing global state, the composition-api offers a solution using composables.

To begin, create a directory called /composables and add a JavaScript file (it's recommended to start the filename with the use prefix) such as useState.js:

import { reactive, toRefs } from "vue";

const state = reactive({
  isMenuOpened: false
});

const toggleMenuState = () => {
  state.isMenuOpened = !state.isMenuOpened;
};

export default {
  ...toRefs(state),
  toggleMenuState
};

The toRefs function converts all properties into refs in a plain object

You can now utilize this composable within your Vue components:

<script>
import useState from "./composables/useState";

export default {
  setup() {
    const { isMenuOpened, toggleMenuState } = useState;

    return {
      isMenuOpened,
      toggleMenuState,
    };
  },
};
</script>

Live Demo: https://codesandbox.io/s/happy-chandrasekhar-o05uv?file=/src/App.vue

Learn more about the composition API and composables here: https://v3.vuejs.org/guide/composition-api-introduction.html

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best way to prevent Firefox from storing the data of a textarea in the local environment?

I have been developing a website locally, and I have noticed that there are numerous <textarea> elements present on the site. One issue I am facing is that whenever I reload the site, the content within the <textarea> remains the same. This pe ...

Tips on deactivating a button after it has been clicked once within a 24-hour period and reactivating it the following day with the use of JavaScript and Angular

Is it possible to disable my button after one click per day, and then automatically re-enable it the next day once a user has entered details using the submit button? I need assistance with JavaScript or AngularJS for this functionality. ...

The optimal method for designing a select menu to ensure it works smoothly on various web browsers

Recently, I encountered an issue with customizing a select menu using CSS and jQuery. After some work, I was able to achieve a result that I am quite pleased with: So far, the styling works perfectly in Mozilla, Opera, Chrome, and IE7+. Below is the curr ...

In JavaScript or Typescript, using the return statement within the .then callback function nested inside the

Looking to filter an array, but it requires calling the database which returns a promise. Here's the code: this.arrayToFilter.filter(myObject => { this.dataBaseService.getSomething(myObject.id).then(something => { // performing som ...

What is the best way to give precedence to non-auto capitalization in input fields on the Input Component from Material UI, especially when using iPads?

The issue I'm encountering is specific to Material UI and IPad, requiring a change in the component used from MUI. Currently, I am utilizing the Input component from Material UI. Upon clicking on the input, the IPad keyboard opens and automatically ...

Exploring the power of Vue3 with reactive nested objects and the inclusion of

It seems like I've encountered a bit of a challenge... Perhaps a bug in Vue3 with Typescript and the composition API, or maybe I'm missing something. I'm facing an issue where I'm not getting any intellisense in my IDE (Webstorm) when ...

The Issue of Promises Chaining in Vue That is Causing Unexpected Behavior

Can’t seem to figure out what I’m missing here, so reaching out for help. Simply put, I want to achieve this in Vue (https://codesandbox.io/s/6zlmkm61m3) function p1() { return new Promise((resolve, reject) => { console.log('p1') ...

Instantiate a child class within an abstract class by utilizing the keyword "this"

Within my code, there is an abstract class that uses new this(). Surprisingly, this action is not creating an instance of the abstract class itself but is generating an instance of the class that inherits from it. Even though this behavior is acceptable i ...

Utilize jQuery's .append() function to dynamically insert content into your webpage

I currently have tab elements set up like this: <div class="tab-pane fade active in" id="tab-a"> </div> To populate the content of that tab with a JavaScript string array, I am using the following code snippet: var full_list = ""; for (var ...

Is the format of the ISOString valid?

How can I verify if a field is in ISOString format? It works fine when I input a valid date such as const create = '2018-08-02T02:07:49.214Z', but it causes an error in the script when I use const create = 'b'; Here is an example: ...

Retrieve the outcome from the PHP webpage

I have recently developed a contact page, but I am experiencing an issue with the submit button's functionality. When I click on the submit button, the form is supposed to send the information to a PHP file on the server-side. However, the button does ...

What is a way to hide or exclude tabs when there is no content to display for a particular tab in Vue?

I'm new to javascript and Vue, and I'm trying to figure out how to hide tabs that don't contain any information. I want to display only the tabs that do have information. Can someone please help me with this? I automatically pull images bas ...

What steps do I need to take to modify a JSON parser?

I need assistance in converting a parser to JSON for a new server response. Previous server response: {"names":[{"name":"Oleg","act":0,"total":0},{"name":"Vitya","act":2," ...

Tips for fixing the Runtime.UnhandledPromiseRejection error when deploying your next.js project on Vercel and Netlify

Encountering an error during deployment on Vercel or Netlify. The same error persists on both platforms. Any suggestions on resolving this issue would be greatly appreciated. Snippet of the Database code: import mongoose from 'mongoose'; const ...

What is the best way to trigger a parent function from a Bootstrap modal within a Vue.js component

In my vue.js component, I am calling a Bootstrap modal within a function. I want to call another function after the modal is closed, but I am facing issues with the scope. this.myFunction() // This works here $('#app-modal-warning').on('hi ...

Passing arrow functions for input validation rules to the Stancil component in Vue

I am attempting to implement an arrow function as input rules, similar to the setup in Vuetify at https://vuetifyjs.com/en/api/v-input/#rules. My approach involves passing rules within an array using the following code: <body> <div id="ap ...

What is the best way to manage HTML code that is delivered through JSON data?

I am dealing with data from a JSON that is in HTML code format. I need to print it as HTML, but currently it is only printing as a string: "content": "More tests\u003cbr /\u003e\n\u003cbr /\u003e\n\u003cdiv class=&bso ...

How come eslint is unable to detect all files within a directory, yet it can detect a single file?

Here is the organization of my files and directories. https://i.stack.imgur.com/YWNw3.png I am looking to set up some eslint rules for my code detection. In my .eslintrc file, I have included these configuration settings. { "extends": "airbnb", "ru ...

Having issues with Vue.js when using Vue-strap Radio Buttons

While developing my web application with vue.js, I encountered an issue with radio buttons when I switched to using bootstrap style. I understand that I need to use vue-strap for proper data binding with bootstrap styled radio buttons in vue.js, but I am s ...

Leveraging the power of HTML 5 to dynamically insert content into a jQuery table

I am experiencing an issue with my jquery stock ticker. It displays the latest stocks including Company Name, stock price, and percentage changed. The stock price can be in GBP, USD, or YEN, but the current ticker does not indicate the currency. I attemp ...