Vuex Tutorial Example From Scratch

Vuex Tutorial Example From Scratch is today’s main topic. VueJS is the front end library to design the interfaces, and it is gaining immense popularity nowadays. Vuex is one of the Vue js’s model implementation, or we can say State of our data representation. So let us talk about Vuex with an example in deep. We are using Vuex 2.0 so, technically it is a Vuex 2.0 tutorial example.

Summary

Vuex 2.0 and VueJS 2.0 Tutorial will go through the practice of how you can set up the dev environment with each other, and we are creating Simple Counter Tutorial.

Purpose

One possible reason I am writing this is showcase how Vuex will play nicely together.

Requirements

For learning Vue.js, I suggest going with my this article Vuejs Tutorial With Example. It will guide you to learn fundamentals of Vue.js 2.0

Vuex

Vuex is a state management pattern + library. It is work as a centralized storage of our data for the whole application. The basic concept is derived from React’s Redux and Flux library. Vuex comes into the picture when our client side application becomes more and more complex. If our application is not more complex, then we should not use Vuex because after using it, if you will not handle it properly then It will become tedious and cumbersome.

It is a self-contained app with the following parts:

  • The state, which is the source of truth that drives our app;
  • The view, which is just a declarative mapping of the state;
  • The actions, which are the possible ways the state could change in reaction to user inputs from the view.

This is an extremely simple representation of the concept of “one-way data flow”:

State Management in Vue

Actions call mutation and mutations mutate the object. It will change the state according to an action triggered. So the state of our application will be changed and according to that component notifies the changes and react according to it.

Vue component first triggers an action by either button clicked or some HTTP request’s response will be received. So action will be triggered. According to action type, the mutation will take place, and then the state will change, and other Vue component will notify about these changes.



State

If you are using Vuex, then you will have only one Single store for each VueJS powered application. Vuex Store is Singleton source of State. Our store contains application state. State management in VueJS with Vuex is straightforward. You just need to modify the state via dispatching the action and not directly because we want to predict the future states. Our store contains application state. 

Mutations

The only way to change the state in a Vuex store is by committing a mutation. We can directly change the state, but we will not do it because we need a snap shot for every step of our project. We need to predict the next state. For the debugging purpose, we will not mutate the state directly, but via mutations.

Actions

Actions are similar to mutations, the differences being that:

  • Instead of mutating the state, actions commit mutations.
  • Actions can contain arbitrary asynchronous operations.

Why you use and do not use Vuex

  1. As per the Author of Redux Mr. Dan Abramov, if your application has so many states and you can not handle with open library then and then, you need to use Redux, in our scope it is Vuex.
  2. If the application gets bigger and bigger, then Vuex is the way to handle the data efficiently and log the every operation with the Vuex store.Vuex store.
  3. The small application does not need Vuex.
  4. If you want to share the state with the other fellow components then and then, you need to use Vuex. Shared state phenomenon uses this kind of libraries. So after understanding the project, if a particular state is consumed by multiple components then and then you have to use Vuex.

Vuex Tutorial Example

Step 1: Configure VueJS 2.0 Application.

We are using a simple VueJS 2.0 configuration. So I am writing one package.json file here, you just need to copy that file and paste it to your package.json file and if not there then create it manually and then copy paste that file.

{
  "name": "vuexpro",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "webpack-dev-server --inline --hot"
  },
  "author": "Krunal Lathiya",
  "license": "ISC",
  "devDependencies": {
    "babel-core": "^6.25.0",
    "babel-loader": "^7.1.1",
    "babel-plugin-transform-runtime": "^6.23.0",
    "babel-preset-es2015": "^6.24.1",
    "babel-preset-stage-3": "^6.24.1",
    "babel-runtime": "^6.25.0",
    "cross-env": "^5.0.5",
    "vue": "^2.4.2",
    "vue-loader": "^13.0.2",
    "vue-template-compiler": "^2.4.2",
    "vuex": "^2.3.1",
    "webpack": "^3.4.1",
    "webpack-dev-server": "^2.6.1"
  }
}



Make sure that you will open CMD as an administrator mode in Windows or put sudo before command if you are using Mac.

npm install

It will install all of our dependencies including Vuex library.

Now, we need to create a webpack.config.js file for configuring webpack server.

copy the following content in it.

// webpack.config.js

module.exports = {
  // This is the "main" file which should include all other modules
  entry: './src/main.js',
  // Where should the compiled file go?
  output: {
    filename: 'bundle.js'
  },
  resolve: {
  alias: {
    vue: 'vue/dist/vue.js'
  }
},
  module: {
    // Special compilation rules
    loaders: [
      {
        // Ask webpack to check: If this file ends with .js, then apply some transforms
        test: /\.js$/,
        // Transform it with babel
        loader: 'babel-loader',
        // don't transform node_modules folder (which don't need to be compiled)
        exclude: /node_modules/
      },
      {
        // Ask webpack to check: If this file ends with .vue, then apply some transforms
        test: /\.vue$/,
        // don't transform node_modules folder (which don't need to be compiled)
        exclude: /(node_modules|bower_components)/,
        // Transform it with vue
      use: {
        loader: 'vue-loader'
      }
    }
  ]
}
}

Step 2: Make index.html and main.js files.

We have configured the development environment and put the following content in it.

<!-- index.html -->

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Vuex Tutorial Example From Scratch</title>
    <link rel="stylesheet" href="bulma.css" />
  </head>
  <body style="overflow-y: hidden;">
    <div id="app">
    </div>
    <script src="bundle.js"></script>
  </body>
</html>

For this project, I have used a Flex CSS Framework called Bulma.

I have included bundle.js file in this file because after all, this is the file we need it finally to up and running with all of our JavaScript code.

Also, I have created a div element with an ID of the app.

Create one folder called src inside root directory. Inside that directory, create one file called main.js

// main.js

import Vue from 'vue';

new Vue({
  el: '#app'
});

Here, I have to create vue object and pass it one parameter, which is bound to that DOM element.

Inside src folder, create one vue component called App.vue.

// App.vue

<template>
  <div class="container">
    Welcome to App Component.
  </div>
</template>

<script>
export default {

}
</script>

Include this component in the main.js file.

// main.js

import Vue from 'vue';
import App from './App.vue';

new Vue({
  el: '#app',
  render: h => h(App)
});

 

npm start

Possible Errors:

Cannot find module ‘is-utf8

Possible Solution:

Uninstall the node_modules folder by the following command.

rm -rf node_modules

It will remove that folder and then open command line terminal in administrator mode and type following command.

npm install

It will fix this issue. And now again type the following command, if you have faced this error.

npm start

Switch to the URL: http://localhost:8000

It will display like “Welcome to App Component.”

Step 3: Create a Vuex Store.

Next step will be to create our Vuex store. So in the src directory, create one folder called the store.Vuex store. So in the src directory, create one folder called the store.

In that, create one file called store.js. Both folder name and the file name is same.store.js. Both folder name and the file name is same.

// store.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
    
});

Here, I have imported Vuex store and used in Vue library. We just pass this store, while creating vue instance in the main.js file. Vuex store and used in Vue library. We just pass this store, while creating vue instance in the main.js file.

// main.js

import Vue from 'vue';
import App from './App.vue';
import store from './store/store.js'

new Vue({
  el: '#app',
  store,
  render: h => h(App)
});

So we have passed our application state to our main vuejs application. Now, we can access its data with the proper methods and proper Vuex flow.

We are building the simple counter application. So first we need to define one state in the store.js file.

// store.js

import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);

const store = new Vuex.Store({
  state: {
    count: 0
  }
})
export default store;

Vuex store is our main application store. It is the single source of truth. All of our application data will be handled by this store. is our main application store. It is the single source of truth. All of our application data will be handled by this store.

In the store, there is state object, which has one object called count. Our main data is right now count because It will be incremented or decremented in future. So single source of truth is count.

We have initialized count with 0.

We are passing the global store into our Vue application instance so that our all child components can access it.

// main.js

import Vue from 'vue';
import store from './store/store';
import App from './App.vue';

const app = new Vue({
  el: '#app',
  store,
  render: h => h(App)
})

Step 4: Make two components: Add and Remove Counter.

Our primary application is to increment or decrement the count. We need to dispatch two actions.increment or decrement the count. We need to dispatch two actions.

  1. Increment
  2. Decrement

We also need to create two vue components inside components folder.

  1. AddCounter.vue
  2. RemoveCounter.vue
// AddCounter.vue

<template>
  <div class="container">
    <div class="field is-grouped">
      <div class="control">
        <button class="button is-primary">Add</button>
      </div>
  </div>
  </div>
</template>

<script>
  export default {
    
  }
</script>




Same as RemoveCounter.vue.

// RemoveCounter.vue

<template>
  <div class="container">
    <div class="field is-grouped">
      <div class="control">
        <button class="button is-primary">Remove</button>
      </div>
  </div>
  </div>
</template>

<script>
import store from '../store/store';

  export default {
   
  }
</script>

We also need to Display the counter, so what we need is that Counter component called Counter.vue file inside components folder.

// Counter.vue

<template>
  <div class="cotainer">
    <div class="notification">
      <h1 class="title" align="center">
        {{ count }}
      </h1>
    </div>
  </div>
</template>
<script>


export default {
 data: {
   count: 0
 }
}
</script>

All these components will be included in the App.vue file to display the whole application.

// App.vue

<template>
  <div class="container">
    <Counter></Counter><br />
    <div class="columns">
      <div class="column is-11">
        <AddCounter></AddCounter>
      </div>
      <div class="column auto">
        <RemoveCounter></RemoveCounter>
      </div>
    </div>
 </div>
</template>
<script>

import Counter from './components/Counter.vue';
import AddCounter from './components/AddCounter.vue';
import RemoveCounter from './components/RemoveCounter.vue';

  export default {
    components : {
      Counter,
      AddCounter,
      RemoveCounter
    }
  }
</script>



Step 5: Create Mutations and Actions.

Inside store folder, we are creating one more folder called mutation types and in that create one JavaScript file called types.js. In this file, we are defining our mutation’s type meaning regarding our application is that we need to export two mutation types name. Increment and Decrement.

// types.js

export const Increment = 'increment';
export const Decrement = 'decrement';

Now, If the user clicks the Add button then one action will be triggered, and that action commits the mutation and state changes and according to that UI will change.

// AddCounter.vue

<template>
  <div class="container">
    <div class="field is-grouped">
      <div class="control">
        <button class="button is-primary" v-on:click="addCounter()">Add</button>
      </div>
  </div>
  </div>
</template>

<script>
import store from '../store/store';
import * as type from '../store/mutationTypes/types';

  export default {
    methods: {
        addCounter(){
          store.dispatch({
            type: type.Increment,
            amount: 20
          })
        }
    }
  }
</script>

Here on button click, and addCounter function will be called, and then that function will dispatch the action type and payload. Switch to the store.js file, We need to add one action, and that action will commit the mutation.

// AddCounter.vue

import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);

const store = new Vuex.Store({
  state: {
    count: 0
  },
    actions: {
    increment (context, payload) {
      context.commit('increment', payload)
  }
})
export default store;

So, we need to create one mutation called ‘increment.’ Remeber, we can not change the state in action, for that, we have to call mutation function to change the state.

// AddCounter.vue

import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state, payload){
      return state.count = state.count + payload.amount;
    }
  },
  actions: {
    increment (context, payload) {
      context.commit('increment', payload)
  }
})
export default store;

We are calling mutation function with the payload. A payload is the data, which is needed to change the counter. In our application, I have put 20 amount to increment the counter.

Now, we need to update Counter.vue file to show the updated counter.

// Counter.vue

<template>
  <div class="cotainer">
    <div class="notification">
      <h1 class="title" align="center">
        {{ count }}
      </h1>
    </div>
  </div>
</template>
<script>

import { mapState } from 'vuex';

export default {
  computed: mapState({
      count: state => state.count
})
</script>

If you will start the webpack-dev-server by typing npm start command, our server had hosted the index.html file at the port 8000.

 

Vuex Example

As you can see, we are incrementing the counter.

Step 6: Follow the same step of Increment to Decrement.

We need to Decrement the counter by following the same step as we have followed in the Increment step.  Go to the RemoveCounter.vue file and write the code that adds remove counter function.

// RemoveCounter.vue

<template>
  <div class="container">
    <div class="field is-grouped">
      <div class="control">
        <button class="button is-primary" v-on:click="removeCounter()">Remove</button>
      </div>
  </div>
  </div>
</template>

<script>
import store from '../store/store';
import * as type from '../store/mutationTypes/types';

  export default {
    methods: {
        removeCounter(){
          store.dispatch({
            type: type.Decrement,
            amount: 20
          })
        }
    }
  }
</script>

Modify the store.js file and add the decrement action as well as decrement counter mutation.

I am showing the whole final store.js file.store.js file.

// store.js

import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state, payload){
      return state.count = state.count + payload.amount;
    },
    decrement (state, payload){
      return state.count = state.count - payload.amount;
    }
  },
    actions: {
    increment (context, payload) {
      context.commit('increment', payload)
    },
    decrement (context, payload) {
      context.commit('decrement', payload)
    }
  }
})
export default store;

Now, the final step would be to put the condition that, if counter gets negative then we will set it to 0.


// Counter.vue

<template>
  <div class="cotainer">
    <div class="notification">
      <h1 class="title" align="center">
        {{ count }}
      </h1>
    </div>
  </div>
</template>
<script>

import { mapState } from 'vuex';

export default {
  computed: mapState({
      count: function(state){
        if(state.count < 0){
          state.count = 0;
          return state.count;
        }
       return state.count;
     }
    })
}
</script>

 

Vue and Vuex example from scratch

So, at last, the application will look like this. You can increment the counter from one component and decrement counter from another element.

We have used mapState(), a helper, because When our component needs to make use of multiple store state getters then To deal with this, we can make use of the which generatesmapState computed getter functions for us.

Our example application is finally over. I am sharing you the code on GitHub.

Github Link: https://github.com/KrunalLathiya/vuexcounter

For more information check out its official website: https://vuex.vuejs.org/en/state.html

Steps:

  1. Clone the repository.
  2. Switch to the root of the project folder and type “npm install.
  3. Now, after install type: npm start
  4. Our primary server is running at http://localhost:8000

If you have any doubt about  Vuex Tutorial Example From Scratch, then ask in a comment below, I am happy to help you out.

You might also like More from author

Leave A Reply

Your email address will not be published.