Managing multiple central stores with Vuex
Tags: vue, vuex, javascript, webdev
Published: 2019-07-08 17:29:33

---
title: Managing multiple central stores with Vuex
published: true
tags: vuejs,vuex,javascript,web-development
canonical_url: https://blog.logrocket.com/managing-multiple-central-stores-with-vuex-74cc44646043
---

[![](https://cdn-images-1.medium.com/max/1024/1*mD6hH2jyPWoyKeE-r-ptxw.png)](https://vuex.vuejs.org/)<figcaption><a href="https://vuex.vuejs.org/">https://vuex.vuejs.org/</a></figcaption>

#### Introduction

While building applications, one of the best practices is to make your application architecture component driven by using the “separation of concerns” concept. This also applies when building applications with Vue.

As you follow a component driven architecture, at some point in time, you’ll need to share data among these components.

How can we share data among these components in a **Vue** application?

[![](https://cdn-images-1.medium.com/max/1024/1*GPjaPKNNUYHU8EsA3Z0JGA.png)]
(https://logrocket.com/signup/)

#### Why Vuex ?

In a simple Vue application having just a few components, sharing data can be achieved using [**Props**](https://vuejs.org/v2/guide/components-props.html) **,** [**Custom Event**](https://vuejs.org/v2/guide/components-custom-events.html) **.**

When your components start growing progressively, it’s advisable to introduce a **Central Event Bus** to serve a standalone service for managing data across the components in your application.

Eventually, your components will build up to form a tree where there will be parents, children, siblings, adjacent siblings etc.

For example, take a registration page which has three different stages. We may come up with four components — 3 to handle the stages and 1 to coordinate and manage the overall operations. You’ll see what I mean in a minute.

Managing data between the parent and children component (and other set of nested components) will get tricky and may easily be messed up while using the aforementioned ways of sharing data — [**Props**](https://vuejs.org/v2/guide/components-props.html) and [**Custom Event**](https://vuejs.org/v2/guide/components-custom-events.html)

So, what’s the best way to share data among nested components?

![](https://cdn-images-1.medium.com/max/691/1*4WmNM3B-R8zy555cr68AVA.jpeg)<figcaption>A system having nested components</figcaption>

The best way to handle data among these type of components is to introduce **Vuex** in your application.

```jsx
Vuex can also be considered as a library implementation tailored specifically for Vue.js to take advantage of its granular reactivity system for efficient updates
```

Conceptually, Vuex may be pictured as a bucket of water that supplies water based on its content, and to whosoever needs it.

You cannot empty a bucket that’s not filled yet.

Vuex acts more or less like a central **store** for all components in the application — a bucket from which you can draw water. The **store** can be accessed by any of the components regardless of the number of (nested) components in an application.

![](https://cdn-images-1.medium.com/max/199/1*aEbrLamj4nefAMavaDNt0w.jpeg)<figcaption>Vuex Abstraction 😃</figcaption>

Let's take a look at the architecture behind Vuex. If the architectural diagram seems a bit confusing, relax. You are definitely covered!

![](https://cdn-images-1.medium.com/max/701/1*KIoNyRO6s_52W68Y-0usJw.png)<figcaption>Vuex Architecture — from the <a href="https://vuex.vuejs.org">docs</a></figcaption>

This article explains different modules of the architecture. We’ll use a familiar exampl: _A counter system that either increments or decrements a counter state_.

#### Getting Started

Vuex can easily be added to a project using any of the following options:

1. **CDN (Content Delivery Network)**

```jsx
Vuex is installed automatically immediately Vue is added
```
```jsx
<script src="/path/to/vue.js"></script>
<script src="/path/to/vuex.js"></script>
```
**2. NPM (Node Packet Manager)**

```jsx
npm install --save vuex
```

**3. Yarn**

```jsx
yarn add vuex
```

Before we can access the properties of Vuex, Vue needs to be aware of the external resource, Vuex, before we can **use**  it.

```jsx
import Vue from 'vue'
import Vuex from 'vuex'
```
```jsx
Vue.use(Vuex)
```

#### **Vuex Fragments**

For those who have some React.js background, _`Vuex`_ is a bit similar to a Redux or a Flux implementation. These are all based on the same general idea.

Based on the architectural diagram shown earlier, we’ll discuss the following modules:

#### **1. State**

_Vuex_ majors on the idea of a store — where items belonging to the store can be shared easily. This **central store** holds the state of the application, and the state can either be _modified_, _accessed or retrieved_ by any components in the application.

A state can also be assumed to be an observer that monitors the life cycle of a property. In this article, the property we’re monitoring is called counter.

![](https://cdn-images-1.medium.com/max/671/1*TOa1pW9i1sjhP6Cro78mLg.jpeg)<figcaption>A central store acting as a singleton to components</figcaption>

Let's create a simple application which has two child components ( **counter and display** ) and a **main** component. The counter component has two buttons, **increase** to add 1 to the counter property, and **decrease** to reduce the counter by 1. The display component displays the current result of the counter while the **main** component _combines_ both to make a single component.

![](https://cdn-images-1.medium.com/max/910/1*gYcNKpodp9VjRvDNPKU_kQ.gif)<figcaption>Accessing counter state</figcaption>

The goal here is to either **update** (_increase or decrease_) the counter or **get** (display) the current value of the counter property. The **state** holds all the properties the application has. In this case, it has a counter property which is initially set to 0.
```jsx
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export const store = new Vuex.Store({

    state: {
        counter: 0
    }
});
```
*State pattern using a Central Store*

How does the counter component gain access to Central Store?

Since we have made _Vue_ aware of _Vuex_. We can now access Vuex properties without raising an alarm :)
```jsx
<template>
  <div>
    <button class="btn btn-primary" @click="increase">Increase</button>
    <button class="btn btn-danger" @click="decrease">Decrease</button>
  </div>
</template>

<script>
  export default {
    name: "app-counter",
    methods: {
      increase() {
        this.$store.state.counter++;
      },
      decrease() {
        this.$store.state.counter--;
      }
    }
  };
</script>
```
*counter component*

From the above code snippet, **$store** is a property from **_Vuex_** which gives access to the **central store.** This is how we access the state of the counter.

Two methods have also been defined_._ The _increase_ method increases the current state of the counter by 1 while the _decrease method_ decreases the current state of the counter by 1.
```jsx
<template>
    <p>
        Counter value is: {{ counter }} </p>
</template>

<script>
    export default {
        name: 'appResult',
        computed: {
            counter() {
                return this.$store.state.counter;
            }
        }
    }
</script>
```
*display component*

In the display component shown above, the counter property is updated with the current counter state using [_computed_](https://vuejs.org/v2/guide/computed.html) property to display the result as the counter changes.

As simple as the _state pattern_ above is, it can easily get messy when the current state needs to be modified and displayed across multiple components.

![](https://cdn-images-1.medium.com/max/801/1*Vvac8-CcGymFoUE2VvI2Eg.jpeg)<figcaption>Downside of State pattern</figcaption>

In the diagram above, the counter state is modified and displayed in Component R2, R3 and R4 respectively. Assuming the modification is the same, the same piece of code would be repeated in the three components. For example, adding a currency symbol to the counter state before being displayed in the components, the currency symbol would be repeated in all the three (3) components.

How can we stick to DRY (Do not Repeat Yourself) concept while accessing modified state(s) across components?

Another fragment we would look into is the _getters,_ it works with the same concept of **get** in Javascript, and it returns the fed object.

#### **2. Getters**

Getters return the state in the central store. This ensures the state is not accessed directly from the store. It is also easier to modify the state before it’s accessed by any of the components in the application.

![](https://cdn-images-1.medium.com/max/761/1*ZSIf178JMeR126x3IQkCYQ.jpeg)<figcaption>Access states or modified states with Getters</figcaption>
```jsx
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export const store = new Vuex.Store({

    state: {
        counter: 0
    },

    getters: {
        /**
         * access counter in state from the paramater 
         */
        addCurrencyToCounter: function (state) {
            return `$ ${state.counter} (dollars)`;
        }
    }
});
```
*Central Store with Getters*

Let’s add a currency symbol to counter it being displayed in display component and see how _getters_ work. **addCurrencyToCounter** (_method in getters in snippet above_) is accessed by the _display_ component to get the current state of the counter.

To access the counter, _addCurrencyToCounter_ is accessed in the object of **$store** called  **getters**.
```jsx
<template>
    <p>
        Counter value is: {{ counter }} </p>
</template>

<script>
    export default {
        name: 'appResult',
        computed: {
            counter() {
                return this.$store.getters.addCurrencyToCounter;
            }
        }
    }
</script>
```
*display Component to display counter*

What if there are lots of methods in the getter object, does the snippet becomes unnecessarily large?

Definitely yes! **_mapGetters_** is a helper object that maps all the _getters_ functions to a property name.
```jsx
mapGetters({
    propertyName: 'methodName'
})
```
```jsx
<template>
    <div>
        <p> Counter value is: {{ counter }} </p>
        <p> Counter incremental value is: {{ increment }} </p>
    </div>
</template>

<script>
    import {
        mapGetters
    } from 'vuex';
    
    export default {
        name: 'appResult',
    
        /**
         * map the method(s) in getters to a property
         */
        // computed: mapGetters({
        //     counter: 'addCurrencyToCounter',
        //     increment: 'incrementCounterByTen'
        // })
    
        /**
         * **** using spread operator ****
         * This is useful when other properties are to be 
         * added to computed proptery
         */
        computed: {
            ...mapGetters({
                counter: 'addCurrencyToCounter',
                increment: 'incrementCounterByTen'
            })
        }
    }
</script>
```
*mapGetters*

How do we know the components that modify the state?

Allowing the component(s) to modify the state directly without tracking which component modified the current state is not ideal. An example is an e-commerce application that has a checkout component, payment component etc. Imagine the itemPrice (state property) is modified by payment component without tracking which component had modified the state. This might result in unforeseen losses.

#### **3. Mutation**

Mutation uses the _setter approach_ in **getters and setters** concept. Before we can access a property, it must have been set. The counter state was initially set to 0. In a situation where the counter needs to be set with a new value, _mutation_ comes into play. It updates **(commit)** the states in the store.

> The updated state done by **mutation** is now reflected in all components accessing the getters in the application.

![](https://cdn-images-1.medium.com/max/739/1*K_5RIpTXZaUxhiujPfHVFw.jpeg)<figcaption>mutation</figcaption>

Let's modify the above example by committing the changes from the counter component using mutation.
```jsx
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export const store = new Vuex.Store({

    state: {
        counter: 0
    },

    getters: {
        /**
         * access counter in state from the paramater 
         */
        addCurrencyToCounter: function (state) {
            return `$ ${state.counter} (dollars)`;
        },

        incrementCounterByTen: function(state) {
            return state.counter + 10
        }
    },

    mutations: {
        increase: function(state) {
            state.counter ++;
        },

        decrement: function(state) {
            state.counter++;
        }
    }
});
```
*mutation*

From the snippet above, the property of the state can be accessed from the parameter of the function. The state update can now be centralized in the central store. Even if the component is the 100th child of the parent, it can update the state and a child from a different parent can also have access to the state.
```jsx
<template>
  <div>
    <button class="btn btn-primary" @click="increase">Increase</button>
    <button class="btn btn-danger" @click="decrease">Decrease</button>
  </div>
</template>

<script>
  export default {
    name: "app-counter",
    methods: {
      // increase() {
      //   this.$store.state.counter++;
      // },
      // decrease() {
      //   this.$store.state.counter--;
      // }

      increase() {
        this.$store.commit('increase');
      },

      decrease() {
        this.$store.commit('decrement');
      }
    }
  };
</script>
```
*Commit mutation methods* 

The **commit** property can also be accessed from $store to set the state to its current value. Apart from **mapGetters** used in mapping methods in getters to property names, there is also **mapMutations** which uses the same concept.

```jsx
mapMutations({
    propertyName: 'methodName'
})
```

Mutation would have been so perfect if it supported both synchronous and asynchronous operations. The methods we have observed so far are synchronous in operation.

_Mutation has no chill._ It’s only concerned about running a task immediately and making sure the state is accessible instantly.

As your web applications grow bigger, you’d likely want to connect to a remote server. This operation would definitely be treated as asynchronous operation since we can’t tell when the request would be done. If handled directly via mutations, the state would be updated beyond the expected result

![](https://cdn-images-1.medium.com/max/571/1*9xBT5N1oqkkg_tuk6lkBUQ.jpeg)<figcaption>mutation handling synchronous activity</figcaption>

How can we handle an asynchronous operation when dealing with mutations?

Since mutations would not run an async operation without messing with the state, its best to keep it out of it. We can always treat it outside mutation, and commit to state in mutation environs when the operation is done. This is where _action_ comes in.

#### **4. Action**

_Action_ is another fragment of Vuex. We can more or less call **actions** as a helper. It's a function that runs any sort of operation before letting mutation aware of what has been done. Its **dispatched** from the component and commits (updates) the state of mutation.

![](https://cdn-images-1.medium.com/max/751/1*rv5er-3AbPQag2qQDNVERw.jpeg)<figcaption>how actions work</figcaption>

Now that the **action** handles the operation, the components have no business interacting with the **mutations** as we did earlier. The components only have to deal directly with the **actions.** The actions in central store can be accessed by the components using the object of **$store** called **dispatch**.

Let's take a quick look at how **actions** are placed in the central store.

Actions do not entirely erase the functions of mutations. As long as the operation we want to run is not async in nature, **mutations** can always take up the job.
```jsx
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export const store = new Vuex.Store({

    state: {
        counter: 0
    },

    getters: {
        /**
         * access counter in state from the paramater 
         */
        addCurrencyToCounter: function (state) {
            return `$ ${state.counter} (dollars)`;
        },

        incrementCounterByTen: function(state) {
            return state.counter + 10
        }
    },

    mutations: {
        increase: function(state) {
            state.counter ++;
        },

        decrement: function(state) {
            state.counter++;
        }
    },

    actions: {
        /**
         * destruct the context, get the commit and call on the appropriate mutation
         */
        increase: function({ commit }) {
            commit('increase')
        },

        decrease: function({ commit }) {
            commit('decrement');
        },

        /**
         * demonstrate an async task
         */
        asyncIncrement: function({ commit }) {
            setTimeout(function(){
                /**
                 * am done, kindly call appropriate mutation
                 */
                commit('increment')
            }, 3000);
        }
    }
});
```
*actions in central store*

How does the counter component now have access to the actions ?

```jsx
increase() {this.$store.dispatch('increase');}
```

The _commit_ which belongs to **mutations** is simply replaced by _dispatch_ belonging to  **actions.**

Just like the way we have _mapGetters_ and _mapMutations_, there is also **mapActions** which is mapped to all methods under _actions_ in the central store.

```jsx
...mapActions({
    increase: 'increase',
    decrease: 'decrease' 
})

OR
...mapActions([
    //this an es6 alternative for increment: 'increment'
   'increase',
   'decrease'
])
```

What we have been doing so far is a unidirectional data transfer. The central store has been distributing data to different components.

How do we now handle a bi-directional flow of data between **central store** and **components**  ?

Getting data from the component, the data can easily be added alongside with the name of action.

```jsx
this.$store.dispatch('actionName', data);
```

The second argument is the **data** (payload) that is sent to the store. It can be **any** type like _string_, _number_ etc. I suggest the payload is always in form of an object to ensure consistency. This also provides the chance to pass in multiple data at the same time.

```jsx
payload = {objValueA, objValueB, .... }
```

Considering an async operation **_asyncIncrement_** in the snippet below, which accepts a value from the component and delivers it to the mutation (commit) to update the state.
```jsx
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export const store = new Vuex.Store({

    state: {
        counter: 0
    },

    getters: {
        /**
         * access counter in state from the paramater 
         */
        addCurrencyToCounter: function (state) {
            return `$ ${state.counter} (dollars)`;
        },

        incrementCounterByTen: function(state) {
            return state.counter + 10;
        }
    },

    mutations: {
        increase: function(state) {
            state.counter ++;
        },

        decrement: function(state) {
            state.counter++;
        },

        asyncIncrement: function(state, incrementalObject) {
            const { incrementalValue } = incrementalObject;
            state.counter += incrementalValue;
        }
    },

    actions: {
        /**
         * destruct the context, get the commit and call on the appropriate mutation
         */
        increase: function({ commit }) {
            commit('increase')
        },

        decrease: function({ commit }) {
            commit('decrement');
        },

        /**
         * demonstrate an async task
         */
        asyncIncrement: function({ commit }, incrementalObject) {
            setTimeout(function(){
                /**
                 * am done, kindly call appropriate mutation
                 */
                commit('asyncIncrement', incrementalObject)
            }, 3000);
        }
    }
});
```
*central store*

Let's add a new _button_ to simulate the async process by adding 5 to the counter state when the operation is completed.
```jsx
<template>
<div>
    <button class="btn btn-primary" @click="increase">Increase</button>
    <button class="btn btn-danger" @click="decrease">Decrease</button>
    <button class="btn btn-info" @click="asyncIncrease(5)">Async Increase by 5</button>
</div>
</template>

<script>
import {
    mapActions
} from 'vuex';
export default {
    name: "app-counter",
    methods: {

        ...mapActions({
            increase: 'increase',
            decrease: 'decrease'
        }),

        asyncIncrease(incrementalValue) {
            const objectValue = {
                incrementalValue
            }

            this.$store.dispatch('asyncIncrement', objectValue);
        }

    },
};
</script>
```
![](https://cdn-images-1.medium.com/max/752/1*j8wfHl9KIqJwRqjROkkd-A.gif)<figcaption>increase counter by 5 after 3ms</figcaption>

#### Conclusion

Vuex gives you the flexibility to manage multiple central stores based on the type of your project structure. You can also group your stores into [modules](https://vuex.vuejs.org/guide/modules.html). The modules act like a container to group more than one central store. This helps to manage stores properly belonging to different groups. Also, it's advisable to group method names which are created in mutations, actions and getters into a single object.

The source code to the project can be found [here](https://github.com/meshboy/vuex-fragment).

_NB: The main components in most of the block diagrams were not connected so as to focus more on the point._
* * *
## Plug: [LogRocket](https://logrocket.com/signup/), a DVR for web apps
 
![LogRocket Dashboard Free Trial Banner](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2017/03/1d0cd-1s_rmyo6nbrasp-xtvbaxfg.png?resize=1200%2C677&ssl=1)
 
[LogRocket](https://logrocket.com/signup/) is a frontend logging tool that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.
 
In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.
 
[Try it for free](https://logrocket.com/signup/).
* * *
The post [Managing multiple central stores with Vuex](https://blog.logrocket.com/managing-multiple-central-stores-with-vuex-74cc44646043/) appeared first on [LogRocket Blog](https://blog.logrocket.com).