Chapter 10. Vuex

This chapter covers

  • Understanding state
  • Using getters
  • Implementing mutations
  • Adding actions
  • Working with Vuex helpers
  • Learning about project setup and modules

In chapter 9, we looked at ways we could extend Vue.js and reuse part of its functionality without repeating code. In this chapter, we’ll look at how we store data in our application and how that data is shared between components. One of the preferred ways of sharing data in an application is by using a library called Vuex. Vuex is a state-management library that helps create a centralized store that can be shared with all the components in the application.

We’ll begin by looking at when we should use Vuex and when we shouldn’t. Certain applications benefit more from Vuex than others. Next, we’ll look at state and how we can centrally locate it. Afterward we’ll explore getters, mutations, and actions. All three allow us to keep track of state in our application. Then we’ll look at Vuex helpers, which will help us eliminate part of our boilerplate code. Last, we’ll see what type of directory structure we can use to fully take advantage of Vuex in larger applications.

10.1. Vuex, what is it good for?

The Vuex state-management library mutates state. It stores state in a central location, which makes it easy for any component to interact with. State is the information or data that supports our application. This is important because we need to access that information in a reliable and understandable way.

If you’ve used other single-page frameworks, such as React, you may be already familiar with several of these concepts. React uses a similar state-management system called Redux. Both Redux and Vuex are inspired by a state-management system called Flux. Flux is an architecture that Facebook created to help build its client-side web applications. It promotes a unidirectional data flow from actions, to a dispatcher, to a store, to a view. This flow helps separate state from the rest of the application and it promotes synchronous updates. You can learn more about flux from the official documentation at https://facebook.github.io/flux/docs/overview.html.

Vuex uses these principles to help mutate state in a predictable, synchronous way. Developers don’t have to worry about synchronous or asynchronous functions changing state in a way that we don’t expect. Let’s say we’re interacting with an API on the backend that delivers a JSON payload to the application. But at the same time a third-party library is changing this information. We don’t want a scenario where the third-party library mutates the data in an unpredictable way. Vuex helps protect us from this scenario by forcing all mutations to be synchronous.

You may be wondering why we need Vuex at all. After all, Vue.js gives us ways to pass information to components. As we learned from the components chapters, we can pass data using props and custom events. You could even come up with an event bus to pass information around and facilitate cross-component communication. You can see in figure 10.1 how this might look.

Figure 10.1. Simple example of using props and an event bus

This works well for smaller applications with only a handful of components. In that scenario, we have to pass information to only a few components. What if our application were larger, with more complexity and levels? You can imagine that inside a larger application, keeping straight all the callbacks, passed props, and the event bus would be difficult.

This is where Vuex comes in. It introduces a more organized way to keep track of our state in one central store. Let’s imagine a scenario where you might consider Vuex. In this scenario we’re creating a blog, and inside that blog we have several components including post, comments, create, edit, and delete. We also have an admin interface where we can ban and add users.

Let’s see how that would look with Vuex. As you can see in figure 10.2, the Edit Bio component is nested under the admin component. The Edit Bio component needs to have access to the user information, so it can update it. When using a central store with Vuex, we can access the store, mutate the information, and commit it straight from the Edit Bio component. This is a significant improvement from having to pass the information down from the root vue.js instance to the admin component then finally to the Edit Bio component using props. Trying to keep the information straight from multiple places would be difficult.

Figure 10.2. How a central store is used with Vuex

With all that said, there’s a price to pay with Vuex: adding Vuex will add more complexity and boilerplate code to your app. As I mentioned, you probably shouldn’t use Vuex for simple apps with only a few components. Vuex thrives in larger applications where state can be more complicated.

10.2. Vuex state and mutations

Vuex uses a single object that contains the state for your complete application. This is also sometimes referred to as the single source of truth. As the name suggests, all the data is stored in exactly one place and isn’t duplicated anywhere in the application.

Tip

It’s worth mentioning that even though we’re using Vuex, we don’t have to put all our state in Vuex. Individual components can still have their own local state. In certain situations, this might be preferable. For example, in your component you might have a local variable that’s only used in that component. That variable should stay local.

Let’s create a simple example of using state with Vuex. For this example, we’ll use a single file. Later, we’ll see how we can add Vuex to a Vue-CLI application. Open a text editor and create a file called vuex-state.html. In this file we’ll display a message that’s stored in the central store and show a counter. When it’s all done it will look like figure 10.3.

Figure 10.3. Creating a simple app using Vuex

We’ll first add a script tag CDN link to both Vue and Vuex. Next, we’ll add in the HTML. For our HTML we’ll use an H1, H2, H3 and a button tag. The h1 tag will display the header, which is a local variable defined in the Vue.js instance. The welcome and counter messages will be computed properties derived from our Vuex store. The button element will trigger an action called increment. Add the code in this listing to the top of the vuex-state.html file.

Listing 10.1. Adding HTML to our Vuex app: chapter-10/vuex-html.html
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/vue"></script>          1
<script src="https://unpkg.com/vuex"></script>         2
</head>
<body>
  <div id="app">
      <h1>{{header}}</h1>                              3
      <h2>{{welcome}}</h2>                             4
      <h3>{{counter}}</h3>                             5
      <button @click="increment">Press Me</button>     6
  </div>

  • 1 Shows a CDN script tag for Vue
  • 2 Shows a CDN script tag for Vuex
  • 3 Denotes the header variable
  • 4 Lists the welcome computed property
  • 5 Shows the counter computed property
  • 6 Notes the button with click action set to increment

Now that we have our HTML in place, let’s begin by adding in a Vuex store. The Vuex store will hold all our data for our example. This will include the msg and count properties.

To update the state, we’ll use something called mutations. You can think of mutations as setters in other programming languages. Setters set values; mutations are what we use to update the state of the application. In Vuex, mutations must be synchronous. In our example, the counter will be triggered only when the button is pressed, so we don’t have to worry about asynchronous code. (Later we’ll look at actions that can help solve the problem when you’re dealing with things that are asynchronous.)

Inside our mutations object we’ll add an increment function that increments state. Take the code in this listing and add it to the bottom of the vuex-state.html file.

Listing 10.2. Add our Vuex state and mutations: chapter-10/vuex-state-mut.html
<script>
  const store = new Vuex.Store({
      state: {
        msg: 'Hello World',            1
        count: 0
      },
      mutations: {
        increment(state) {             2
            state.count++;
        }
      }
  });

  • 1 The Vuex.Store holds state information.
  • 2 Shows the mutations that increment the state

We have our HTML and Vuex store in place, and we can now add the logic that connects everything. We want to make sure that our template displays the msg and counter from the Vuex state and that we can update that count.

Create a Vue.js instance with a new data function. This will return the local header property that displays Vuex App. In the next section, we’ll add a computed property which will have two functions, welcome and counter. The welcome property will return store.state.msg. The counter will return store.state.count.

Finally, we’ll need to create a method called increment. To update the store and access the mutations we set up in Vuex, we can’t call the mutation directly. We must use a special function called commit. This will tell Vuex to update the store and commit the change, so to speak. The store.commit('increment') does the commit to the mutation we created. Add the following code to the vuex-state.html file under the code you created in listing 10.2.

Listing 10.3. Adding our Vue.js instance: chapter-10/vuex-instance.html
new Vue({
    el: '#app',
    data() {
      return {
        header: 'Vuex App'               1
      }
    },
    computed: {
      welcome() {
        return store.state.msg           2
      },
      counter() {
        return store.state.count;        3
      }
    },
    methods: {
      increment() {
        store.commit('increment')        4
      }

    }
});
</script>
</body>
</html>

  • 1 Shows the header property that displays the message
  • 2 The computed property returns the msg state.
  • 3 The computed property returns the counter state.
  • 4 The increment method triggers the Vuex increment mutation.

Now we have a fully functional app that uses Vuex! Click the button a few times, and you should see the counter increment by one after each button click.

Let’s update this application so that each button click updates the count by 10. If you look closely at the mutations increment function, it has only one argument: state. However, we can pass another argument to it: we’ll call it payload. This payload can be sent from the increment method we created in the root Vue.js instance.

Take the vuex-state.html file and copy it into a new file called vuex-state-pass.html. This file will hold our new application, which shows how to pass in a payload.

As you can see in listing 10.4, we need to update only the mutations object and the increment method. Add another argument called payload to the increment mutation. The payload will be added to the state.count. Inside the increment method, add 10 as another argument to the store.commit. Update the vuex-state.html as shown here.

Listing 10.4. Passing payload into a mutation: chapter-10/vuex-state-pass-1.html
...
mutations: {
  increment(state,payload) {        1
      state.count += payload;
  }
}
...
methods: {
  increment() {
    store.commit('increment', 10)   2
  }
...

  • 1 The increment mutation accepts a payload and adds it to the count.
  • 2 The increment method now passes 10 to the mutation.

Save the vuex-state-pass.html file and reload your browser. After clicking the button, it should now increment by 10 instead of by 1. If it’s not loading correctly, check your web browser’s console. Make sure you didn’t have any typos.

10.3. Getters and actions

In the previous example, we directly accessed the store from our computed properties. What if we had multiple components that needed to access these computed properties? What if we wanted to always display a welcome message in all caps? This is where getters can help us out.

Inside Vuex, we have something called getters. With getters, all components can access the state in the same way. Let’s continue with our example from section 10.2. We’re going to update it with getters instead of directly accessing the state in our computed properties. In addition, we want the getter for msg to convert the message to all uppercase letters.

Take the vuex-state-pass.html file from the previous example and copy it to vuex-state-getter-action.html. To make things simple, we’ll leave the HTML the way it was before. When it’s all done it should look like figure 10.4.

Figure 10.4. Hello World app using setters and actions

You can see that the Hello World message is now in capital letters. Clicking the Press Me button increments the counter as it did in the last example.

Inside your newly created vuex-state-getter-action.html file, look for the Vuex.Store below the <script> tag. Below the mutations object add a new object called getters. Inside getters we’ll create msg and count as you can see in listing 10.5. Both msg and count take one argument, state.

In our msg getter, we’ll return state.msg.toUppercase(). This will ensure that whenever we use the msg getter, it will return the value in all caps. For our count getter, it will return state.count. Update the vuex-state-getter-action.html with the new getters object under mutations.

Listing 10.5. Adding new getters: chapter-10/vuex-state-getter-action1.html
...
mutations: {
  increment(state,payload) {
      state.count += payload;
  }
},
getters: {                               1
    msg(state) {                         2
      return state.msg.toUpperCase();
    },
    count(state) {                       3
      return state.count;
    }
},
...

  • 1 The new getters object defines getters for Vuex.
  • 2 The msg getter returns msg in all caps.
  • 3 Shows the count getter

Actions are another integral part of Vuex. I previously mentioned that mutations are synchronous. But what if we’re dealing with asynchronous code? How can we be sure that our asynchronous code will still affect state? That’s where actions in Vuex comes in.

Let’s imagine in our example that we are accessing a server, and we’re waiting for a response. This is an example of an asynchronous action. Unfortunately, mutations must be synchronous, so we can’t use that. Instead, we’ll add the asynchronous operation using a Vuex action.

In this example we’ll create a delay using a setTimeout. Open the vuex-state-getter-action.html file and add a new object called actions after the getter object we created. Inside that object, we’ll have our increment action that takes a context and payload. The context is what we’ll use to commit our changes. We’ll wrap our context.commit inside a setTimeout. This is so we can simulate a delay from a server. We can also pass a payload to the context.commit. This will get passed to the mutation. Update the code based on this listing.

Listing 10.6. Adding actions: chapter-10/vuex-state-getter-action2.html
...
},
actions: {                                   1
  increment(context, payload) {              2
    setTimeout(function(){
      context.commit('increment', payload);  3
    },2000);
  }
}
...

  • 1 The actions object is used for asynchronous and synchronous actions.
  • 2 The increment function accepts a context and payload.
  • 3 This triggers the increment mutation and passes the payload to it.

Now that we’ve updated our Vuex.Store, we can move on to the root Vue.js instance. Instead of accessing the store directly, we’ll update the computed property to access the getters instead. We’ll also update the increment method. We’ll use the store.dispatch('increment', 10) to access the new Vuex action we created.

The first argument of dispatch is always the name of the action. The second argument is always the payload that will get passed into the action.

Tip

The payload can be a simple variable or even an object.

Update the vuex-state-getter-action.html code with the new Vue.js instance from this listing.

Listing 10.7. Updating the Vue.js instance: chapter-10/vuex-state-getter-action3.html
...
new Vue({
    el: '#app',
    data() {
      return {
        header: 'Vuex App'
      }
    },
    computed: {
      welcome() {
        return store.getters.msg;         1
      },
      counter() {
        return store.getters.count;       2
      }
    },
    methods: {
      increment() {
        store.dispatch('increment', 10);  3
      }

    }
});
...

  • 1 The computed property welcome returns the getters msg.
  • 2 The computer property counter returns the getters count.
  • 3 The method dispatches the increment action.

Load the app and click the button a few times. You’ll notice a delay, but the counter will update by 10 after each press.

10.4. Adding Vuex to Vue-CLI with the pet store app

Let’s return to the pet store application that we’ve been working on. If you remember the last time we worked on it, we added fancy animations and transitions. Now that we’ve learned the basics of Vuex, let’s add it to the mix.

Let’s move the product data into the store. If you recall from the previous chapters, we initialized the store in the created hook of the Main component in the pet store application. Instead, we’ll have the create hook dispatch a new action that will initialize the store inside Vuex. We’ll also add a new products computed property that retrieves our products using a Vuex getter that we’ll set up. When all is done it will look and behave the same as it did before, as seen in the figure 10.5.

Figure 10.5. Showing the completed pet store application

10.4.1. Vuex installation in Vue-CLI

To begin, let’s install Vuex! This is straightforward. If you haven’t already, retrieve the latest version of the pet store application that we last worked on in chapter 8. Or you can download the completed code for this chapter from GitHub at https://github.com/ErikCH/VuejsInActionCode.

Open a terminal window and change directories into the root of the pet store application folder. Run the following command at the prompt to install the latest version of Vuex and save it into the package.json file in the pet store application:

$ npm install vuex

Next, we’ll need to add the store to the main.js file in the src folder. We haven’t created the store yet, but let’s import it anyway. By convention, the store is usually located in the src/store/store.js file. This is up to you, and different developers come up with different conventions. For now, this will work for us. Later in the chapter, we’ll discuss alternative folder structures with something called modules.

Inside the root Vue.js instance, we need to add the store, as shown in the following listing. Add the store to the root instance under router. By the way, because we’re using ES6, we can use the shorthand store, instead of store: store.

Listing 10.8. Updating the main.js file: chapter-10/petstore/src/main.js
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an
 alias.
import Vue from 'vue'
import App from './App'
import router from './router'
require('./assets/app.css')
import { store } from './store/store';   1

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  store,                                 2
  template: '<App/>',
  components: { App }
})

  • 1 Imports the store into the main.js file
  • 2 Adds it into the Vue.js instance

Now that we’ve added the store into the root instance, we can access it throughout the application. Create a file in src/store/store.js. This file will be our Vuex store and hold the information for the products in our pet store application. At the top of the file, add two import statements, one each for Vue and Vuex. Next, we’ll add a Vue.use(Vuex). This will connect everything.

Inside the main.js file, we imported store from ./store/store. We need to export a store object inside the store.js file, so that the main.js file can import it. As you can see in listing 10.9, we export a const store of Vuex.Store.

We’ll first add our state and mutations objects. The state object will hold an empty object called products. We’ll load that using our initStore soon. Our mutations will be called SET_STORE. The mutation will take the passed-in products and assign it to state.products. Inside the newly create src/store/store.js file, add the code from this listing.

Listing 10.9. Creating the main.js file: chapter-10/store-part1.html
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);                            1


export const store = new Vuex.Store({     2
  state: {                                3
    products: {}
  },
  mutations: {                            4
    'SET_STORE'(state, products) {
      state.products = products;
    }
  },
  ...

  • 1 Sets Vuex with Vue
  • 2 Exports Vuex.Store so it can be later used in the main.js file
  • 3 The state object shows products.
  • 4 The mutations object shows our set store function.

We need to add the action and getter to the store. The getter will return products. The action is a little more complicated. What we want to do is move the created hook code that uses Axios to read the static/products.json file to the actions object in Vuex.

Remember that I mentioned that mutations had to be synchronous and that only actions inside Vuex would accept asynchronous code? To get around this, we’ll put the Axios code inside a Vuex action.

Create the actions object inside the store.js file and add initStore. Inside this action, copy and paste the created lifecycle hook from the components/Main.vue file. Instead of assigning the response.data.products to the products object, we’ll now use the commit function to trigger our mutation. We’ll pass in the response.data.products as the payload to SET_STORE. After all is done, it should look like this.

Listing 10.10. Adding actions and getters to store.js: chapter-10/store-part2.html
...
actions: {                                           1
  initStore: ({commit}) => {                         2
    axios.get('static/products.json')
    .then((response) =>{
      console.log(response.data.products);
      commit('SET_STORE', response.data.products )
    });
  }
},
getters: {                                           3
  products: state => state.products
}
});

  • 1 The actions object used for asynchronous code
  • 2 The initstore action commits the mutation.
  • 3 The products getter returns the store for products.

We’re getting close, and now all we need to do is update the Main.vue file so it uses the Vuex store instead of the local products object. Open the src/components/Main.vue file and look for the data function. Remove the line products: {}. We’ll now access it from a computed property that returns the store.

Look for the computed properties after the methods inside Main.vue. You should see cartItemCount and sortedProducts. Add a new computed property called products and have it return the products getter.

Keep in mind that because we added the store to the root Vue.js instance in the main.js file, we don’t have to do any special imports. Also, the store is always accessed by this.$store when using Vue-CLI. Make sure to remember the dollar sign or you’ll get an error. Add the products computed property to the Main.vue file, as shown here.

Listing 10.11. Adding product’s computed property: chapter-10/computed-petstore.html
computed: {                                 1
  products() {
    return this.$store.getters.products;    2

  },
...

  • 1 The computed property for the Main.vue file
  • 2 The computed property for products returns getters for products.

Locate the created hook that initialized the products object. Delete the contents of that object and instead have it call the initStore action we created earlier in the Vuex store. As we did with our previous example, use dispatch to trigger the action. Update the created hook inside the Main.vue file so it triggers the Vuex initStore action, as shown in this listing.

Listing 10.12. Updating created hook: chapter-10/created-petstore.html
...
},
created: function() {
  this.$store.dispatch('initStore');       1
}
...

  • 1 Dispatches the code to initialize the Vuex store

That should be it. Run npm run dev from the console and you should see a window open with the pet store application. Try adding items to the cart and verify that all is working. If things aren’t working, check the console for errors. It’s easy to accidentally type Vuex.store instead of Vuex.Store inside the src/store/store.js file. Beware of these problems!

10.5. Vuex helpers

Vuex gives us a handful of helpers that can be used to reduce the amount of verbosity and repetition when adding getters, setters, mutations, and actions to our application. You can find a full list of all the Vuex helpers in the official guides at https://vuex.vuejs.org/en/core-concepts.html. Let’s look at these helpers and see how they work.

The first helper you should know about is mapGetters. This helper is used to add all our getters to our computed properties, without having to type every one of them. To use mapGetters we’ll need to import it into our component first. Let’s look at our pet store application one more time and add in the mapGetters helper.

Open the src/components/Main.vue file and look for the script tag. Inside that tag you should see an import for the header component. Right after that import, add in the mapGetters from Vuex as seen here.

Listing 10.13. Adding mapGetters: chapter-10/map-getter.html
...
...
<script>
import MyHeader from './Header.vue';
import {mapGetters} from 'vuex';           1
export default {
...

  • 1 Imports the mapGetters from Vuex

Next, we’ll need to update our computed property. Look for the computed property for products that we added earlier. Delete it and add a new mapGetters object.

The mapGetters object is unique and to add it correctly, we need to use the ES6 spread operator which expands our expression in places where zero or more arguments are expected. You can find more information on the ES6 spread syntax from the MDN docs at http://mng.bz/b0J8.

The mapGetters will make sure that all our getters will be added as if they were computed properties. As you can imagine, this syntax is much simpler and cleaner than having to write a computed property for each getter. Each getter is listed in an array inside mapGetters. Add the mapGetters to the Main.vue file.

Listing 10.14. Adding mapGetters to computed properties: chapter-10/map-getter2.html
...
},
computed: {
  ...mapGetters([              1
      'products'               2
  ]),
  cartItemCount() {
...

  • 1 Shows the mapGetters helper array
  • 2 Shows the list of getters

If you run npm run dev, you’ll see that our pet store application runs normally. Using mapGetters in our application isn’t too useful, but as it grows and we add more getters, this will save us time.

The other three helpers you should know about are mapState, mapMutations, and mapActions. All three behave the same way and are useful to help reduce the amount of boilerplate code you need to write.

Let’s imagine you have several pieces of data in your store. In this instance, you don’t need any getters and you’ll be accessing the state directly from your component. In this case, you might use the mapState helper inside your computed properties.

Listing 10.15. mapState example: chapter-10/map-state.html
import {mapState} from 'vuex'         1
...
computed: {
  ...mapState([                       2
      'data1',
      'data2',
      'data3'
  ])
}
...

  • 1 Imports mapState from Vuex
  • 2 Uses the spread operator to define mapState and variables

As with mapState and mapGetters, let’s say you also have several mutations you want access to in your component. You can use the mapMutations helper method to make this easy (shown in the following listing). The mut1 in the listing maps this.mut1() to 'this.$store.commit('mut1').

Listing 10.16. mapMutations example: chapter-10/map-mut.html
import {mapMutations} from 'vuex'      1
...
methods: {
  ...mapMutations([                    2
      'mut1',
      'mut2',
      'mut3'
  ])
}
...

  • 1 Imports mapMutations from Vuex into component
  • 2 The mapMutations helper adds these methods.

Finally, we’ll look at the mapActions helper. This helper maps actions to our app, so we don’t have to create every method and have it dispatch each action. Using the same example, let’s say this application also has some asynchronous operations. We can’t use mutations, so we must use actions instead. We created these in Vuex and now we need to access them in our component method object. Adding mapActions to our methods will take care of this. The act1 maps this.act1() to this.$store.dispatch('act1'), as shown in listing 10.17.

Listing 10.17. mapActions example: chapter-10/map-actions.html
import {mapActions} from 'vuex'     1
...
methods: {
  ...mapActions([                   2
      'act1',
      'act2',
      'act3'
  ])
}
...

  • 1 Imports the mapActions from Vuex
  • 2 The mapActions helper adds the act1, act2, and act3 methods.

These helpers will come in handy as your application grows, and it will cut down on the amount of code you need to write. Keep in mind that you’ll need to plan the names in your store because they’ll map out to the names in your components as you use these helpers.

10.6. A quick look at modules

In the earlier sections of this chapter, we created a store.js file in the src/store directory for the pet store application. This worked well for our relatively small application. However, what if our application were much larger? The store.js file would quickly become bloated and it would be difficult to keep track of everything in it.

The Vuex solution for this is modules. Modules allow us to divide our store into smaller pieces. Each module has its own state, mutations, actions, and getters, and you can even nest modules inside it.

Let’s refactor our pet store application to use modules. First, we’ll need to keep our store.js file; however, we need to create a new folder named modules inside our store folder. Inside that folder create a file called products.js. The folder structure should look like figure 10.6.

Figure 10.6. Folder structure for modules

Inside the products.js file, we’ll need to create four objects: state, getters, actions, and mutations. We’ll need to copy and paste each of the values from our store.js to the products.js file.

Open the src/store/store.js file and start copying over the code. When you’re done, your products.js file should look like the following listing.

Listing 10.18. Adding products modules: chapter-10/products-mod.js
const state = {                                1
    products: {}
};

const getters = {                              2
    products: state => state.products
};

const actions = {                              3
    initStore: ({commit}) => {
      axios.get('static/products.json')
      .then((response) =>{
        console.log(response.data.products);
        commit('SET_STORE', response.data.products )
      });
    }
};

const mutations = {                            4
    'SET_STORE' (state, products) {
      state.products = products;
    }
};

  • 1 Holds all the Vuex state
  • 2 Holds all the Vuex getters
  • 3 Holds all the Vuex actions
  • 4 Holds all the Vuex mutations

After adding everything to the product.js file, we need to create an export. This will allow the file to be imported into the store.js file. At the bottom of the file, add an export default. This is an ES6 export command that allows you to import it from other files.

At the bottom of product.js, add the default export.

Listing 10.19. Adding the export: chapter-10/products-export.js
...
export default {          1
    state,
    getters,
    actions,
    mutations,
}

  • 1 Shows the ES6 export of everything

We’ll need to update the store.js file. In this file we’ll add a new module object, and in this object, we can list all the modules we added. Make sure to add an import to the modules/products file we created.

In our case, we have only one, so we’ll go ahead and add it into the module object. Make sure to delete everything in the Vuex.Store so it matches the following listing.

Listing 10.20. New store.js file: chapter-10/store-update.js
import Vue from 'vue';
import Vuex from 'vuex';
import products from './modules/products';       1

Vue.use(Vuex);


export const store = new Vuex.Store({
  modules: {                                     2
    products
  }

});

  • 1 Imports the products module
  • 2 The modules object lists all modules.

Once we have the modules imported, we’re ready to go. Refresh the application and it should behave as it always has.

Namespaces with Vuex

In certain larger applications, breaking up your store into modules might present a problem. As the program grows and more modules are added, the names of your actions, getters, mutations, and state might collide. You might, for example, name two getters with the same name in two different files accidentally. Because everything in Vuex shares the same global namespace, you’ll get a duplicate getter key error in your console when this happens.

To alleviate this problem, you can use namespaces. By setting the namespaced: true at the top of your Vuex.store you can break up your modules per namespace. To learn more about namespaces and how to set this up in your file, please check out the Vuex official documentation at https://vuex.vuejs.org/en/modules.html.

Exercise

Use your knowledge from this chapter to answer this question:

  • What are several advantages of using Vuex over the normal data passing of a Vue.js application?

See the solution in appendix B.

Summary

  • You can restructure your application to use centralized state management.
  • You can access the data store inside the application from anywhere.
  • You can avoid problems with your application store getting out of sync by using mutations and actions with Vuex.
  • You can use Vuex helpers to reduce the amount of boilerplate code needed.
  • In larger applications, you can use modules and namespaces to keep state more manageable.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset