Skip to main content

Vuex State Management Sample


Vuex is a state management pattern or state management library. Vuex makes data management easy and more maintainable in the application. Vuex main target of integration with Vue.js library. 

In simple words, Vuex is a data store that supplies or provide data to Vue components with much consistently, more efficiently by making code more simple. Transferring of data between the component can be done effectively using Vuex when comparing with the traditional way(Vue.js passing data by input parameters). Vuex pattern is similar to Redux, Flux existing libraries for state management.

Vuex Core Building Blocks:

Actions: Actions are task performers which have the capabilities to do either synchronous or asynchronous operations. In Vuex actions are used to invoke the rest API's to fetch the data and then actions call mutations to change the store state. To invoke mutations actions use a command called 'commit'. This 'commit' command invokes appropriate mutation and receives the rest API data as input to save into the store state.

Mutations: Mutations are to perform mutable operations. In Vuex the only option to change the state of the store is to use mutations. So the only way to add or update the data of the Vuex store is done by mutations.

State: State is a simple javascript object literal. A Vuex store saves or holds the data in the state object.

Getters: Getters are to perform tasks to retrieve the data from the Vuex store state. Getters are helped to retrieve data and then we can bind the data to components. So using these Getters in n-number of Vue Components can share the same data from the Vuex store.

Create A Sample Vue App:

To learn Vuex implementation step by step, here we are going to implement a sample Vue application.
Here I'm Vue CLI(command line interface) to operate or create Vue application.
Command To Install Vue CLI Globally On Your System:

npm run -g @vue/cli
Command To Create Vue App:

vue create your_application_name
After creating sample application run the following command to start the application.
Command To Run Vue App:

npm run serve
After the application starts then output shows as below.

Test API:

We are going to use a free development rest API in our sample application to consume the data. Here we are going to use 'Dummy Rest API Example' a free hosted API for developers.
Dummy Rest API Example
http://dummy.restapiexample.com/
Sample dummy rest API output shows as below(screenshot to understand JSON response structure and it's property name that we going to bind in our sample app)

Install Vuex And Axois:

Vuex package needs to install to implement store in our Vue application. Axios package installs to help to fetch API data with easy steps. So run the following commands to install both the packages.
Command To Install Vuex Package

npm install Vuex
Command To Install Axios Package

npm install Axios

Add A Store Folder And index.js File:

Now let's create a separate folder structure to save them all store related files in the folders as below.

In-store management of Vue application will have an n-number of stores(like example student store, teachers store, employee store, account store, etc). Each store will have it's own 'js' file to maintain store and all these store files will be saved under the folder 'modules'
Now let's create an index.js file in the 'store' folder. This index.js file is like a global store that will hold all other application stores and will expose them to the components.
src/store/index.js:
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export default new Vuex.Store({
    modules:{
        
    }
})
  • (Line:4) To load or integrate Vuex into the Vue js then Vuex is passed parameter to 'Vue.use()' method. This method is similar to the middleware configuration in other frameworks
  • (Linet:6-10) Create an instance of the Vuex Store and this store should be exposed to the application by using the 'export' key. On initializing the Vuex Store expects configurations like 'state', 'mutation','getters','actions', etc. Here we can see we have configured modules property with an empty object literal. This module will be configured with our individual store module in the upcoming steps.

Register Store In main.js:

To make our store accessible to our Vue application need to register our global store index.js file in our main.js.
src/main.js:
import Vue from 'vue'
import App from './App.vue'
import store from './store/index'

Vue.config.productionTip = false

new Vue({
  store,
  render: h => h(App),
}).$mount('#app')
  • (Line:3) index store imported into the main.js file.
  • (Line:8) our global store(src/store/index.js) configured into the entry Vue instance of the application. This configuration makes our store can be accessed into the Vue application components.

Create An Employee Store Module:

In this Vue sample, we are going to work on employee data. So here we are going to create an employee-store module.
src/store/module/employee.js:
const state = {};

const getters = {};

const actions = {};

const mutations = {};

export default {
    state,
    getters,
    actions,
    mutations
}
  • Here we created an employee-store module with a basic skeleton structure of the store.
  • we can observe the core building block of the store like 'state', 'getters', 'actions', 'mutations', and all are initialized as object literal.
  • (Line: 9-14) exposing the store configuration to make it accessible to the application.
  • (Line: 1) the state is the storage area of application data. All the API data that going to be rendered or utilized by the application will be stored in the state object. So for our sample, all our employee data will be stored in this 'state' object as well.
  • (Line: 3) the getters contain all the filters or methods for fetching data to Vue components in the application from the 'state' object.
  • (Line: 5) the actions perform the tasks like fetching API data and stores the data into the 'state' object.
  • (Line: 7) the mutations perform the tasks like manipulating of data in the store state object

Register Employee Module Store In Global Store index.js:

All module-level stores need to be registered in index.js file to expose them to the application through a single pipeline of the store.
src/store/index.js:
import Vue from 'vue';
import Vuex from 'vuex';
import employee from './modules/employee';

Vue.use(Vuex);

export default new Vuex.Store({
    modules:{
        employee
    }
})
  • (Line: 9) 'employee' store module registered in the Vuex.Store instance.

Create An Employee Vue Component:

In this sample, we are going to work on employee data, so to display or operate on that data we are going to create an 'Employee.vue' Vue component.
src/components/Employee.vue:
<template>
    <div></div>
</template>

<script>
export default {
    name: "Employee"
}
</script>
Now update the App.vue with our 'Employee' Vue component as follow:
src/App.vue:
<template>
  <div id="app" class="container">
    <h1>Employees</h1>
    <Employee />
  </div>
</template>

<script>
import Employee from './components/Employee.vue'

export default {
  name: 'App',
  components: {
    Employee
  }
}
</script>
  • App.vue component is the root component of our application. All our child component will be registered under this root component
  • (Line: 14) 'Employee' component registered inside with the 'App' Vue component.
In our application folder structure, we can observe the 'Public' folder inside it we can observe the index.html file this our HTML file that's gets loaded on accessing our application. Here we are going to use 'Bootstrap' for design, so add the following style tag on the 'public/index.html' file just above the closing tag of 'head'.
public/index.html:(just above closing tag of head)
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
Now run our Vue application and the output shows as below:

Employee Store Actions To Call API :

Actions meant to be a trigger API calls for an application when using Vuex Store. So now we need to call API to fetch all employees from the test API. After a successful API calls, actions will pass the response data to the store state by calling mutations using the 'commit' command('commit' command triggers mutations).
src/store/module/employee.js:
import axios from "axios";

const state = {};

const getters = {};

const actions = {
    async fetchEmployees(){
        const response = await axios.get("http://dummy.restapiexample.com/api/v1/employees");
        console.log(response.data);
    }
};

const mutations = {};

export default {
    state,
    getters,
    actions,
    mutations
}
  • Axios library will be used for API communication with simple steps in our sample application.
  • (Line: 8-11) In 'actions' we have implemented a method 'fetchEmployees' where we are going to consume the employee API data. For now, we added to console log to check the data later code will update to save the data 'state' object.

Call Store Action From Vue Component:

To load employee data on our application page loads, then need to access the action method into our Vue component.

To access actions Vuex offers 'mapActions' method like a mapper method, which returns actions method references into the Vue component. The 'mapActions' method takes input parameters as an array of names of the action methods. So on specifying the array of actions method all those will be referenced into the Vue component. In our Vue component, 'mapActions' are declared inside of the 'methods' property.
src/components/Employee.vue:
<template>
    <div></div>
</template>

<script>
import { mapActions } from "vuex";
 
export default {
    name: "Employee",
    methods:{
        ...mapActions(['fetchEmployees'])
    },
    created(){
        this.fetchEmployees();
    }
}
</script>
  • (Line: 6) mapAction got imported from the Vuex Library.
  • (Line: 10-12) mapAction that takes the input parameter as an array of action names and it was declared inside of the Vue component 'method' object. After initializing the mapAction method then all the action functions can be accessed using component 'this' scope.
  • (Line: 13-15) 'Created' method is a life-cycle method of the Vue component which will be executed on the creation of the component. So here we will try to invoke the employee API by calling the actions related function like 'fetchEmployess'.
Now run the application and check the browser console check the output as below:

Action Use Commit Command To Save Response Data To State Object:

To save or update the data to state object is only done by using the mutations. But actions should not call mutations directly. So actions use the 'commit' command which will indirectly invoke the mutations.
src/store/module/employee.js:
import axios from "axios";

const state = {
    employees = []
};

const getters : {};

const actions = {
    async fetchEmployees({commit}){
        const response = await axios.get("http://dummy.restapiexample.com/api/v1/employees");
        commit('setEmployees', response.data.data);
    }
};

const mutations = {
    setEmployees:(state,data) => {
        state.employees = data;
    }
};

export default {
    state,
    getters,
    actions,
    mutations
}
  • (Line: 4) 'employees' property created inside the state object, this property will hold the list of employees.
  • (Line: 17-19) 'setEmployees' method is used to update the state object with the employee's data.
  • (Line: 12) fetchEmployees(actions method) uses the commit command to invoke the mutation. 'commit' command takes input parameters like the mutations method name(like 'setEmployees') as the first parameter and rest API data as the second parameter.

Create Getters To Fetch Data From State:

Need to create Getters to fetch data from the state object.
src/store/modules/employee.js:
import axios from "axios";

const state = {
    employees : []
};

const getters = {
    allEmployees:(state) => state.employees
};

const actions = {
    async fetchEmployees({commit}){
        const response = await axios.get("http://dummy.restapiexample.com/api/v1/employees");
        commit('setEmployees', response.data.data);
    }
};

const mutations = {
    setEmployees:(state,data) => {
        state.employees = data;
    }
};

export default {
    state,
    getters,
    actions,
    mutations
}
  • (Line: 8) 'allEmployees' getter method fetches the employee's data from the state object. Here you can observe the input parameter as a 'state' object, this input parameter will automatically be passed by Vuex internally on invoking or accessing the getters(eg: 'allEmployees' getter)
Now Vue component will access the store getters for data binding. The best way to access the store getters is accessed as computed properties. Because computed properties will always get the latest changes of the data so assigning getters as computed props will help to fetch the latest data to our Vue component.

So Vuex provides 'mapGetter' instance to access the store getters into the Vue component. 'mapGetter' expects an array of getters names as the input parameter. On initializing 'mapGetter' inside of the computed object of VueComponent, then the all getter's names in the array will become the computed properties of the Vue component which means store getters props or method names can be directly used in Vue component as properties for data binding.
src/components/Employee.vue:
<template>
  <div class="row">
    <div class="card" style="width: 18rem;" v-for="emp in allEmployees" v-bind:key="emp.id">
      <div class="card-header">{{emp.employee_name}}</div>
<ul class="list-group list-group-flush"> <li class="list-group-item">Salary: {{emp.employee_salary}}</li> <li class="list-group-item">Age: {{emp.employee_age}}</li> </ul> </div> </div> </template> <script> import { mapActions, mapGetters } from "vuex"; export default { name: "Employee", methods: { ...mapActions(["fetchEmployees"]) }, computed: { ...mapGetters(["allEmployees"]) }, created() { this.fetchEmployees(); } }; </script>
  • (Line: 23) using mapGetters, store getter properties, or method is declared inside of the Vue component computed object. On doing this mapGetters initialization now 'allEmployees' will become as the computed property of the 'Employee.vue' Vue component.
  • (Line: 3) 'allEmployees' computed property object is used for the data binding.
Now run the application and the output shows below:

Update Employee Store For Adding New Employee: 

Now update the employee module store for creating the new employee as follow:
src/store/modules/employee.js:
// code hidden for display purpose

const actions = {
  async addEmployee({ commit }, newEmployee) {
     // Note:-
     // Dummy Rest API Example create API returning returning cross-orgin issue
     // so i'm explaining by mocking data here
     
    //   const response = await axios.post("http://dummy.restapiexample.com/create", newEmployee);
    //   commit('addEmployee', response.data);


      const mapNewEmployee = {
          id:0,
          employee_name: newEmployee.name,
          employee_salary: newEmployee.salary,
          employee_age: newEmployee.age,
          profile_image:""
      }
      commit('addEmployee', mapNewEmployee);
  },
};

const mutations = {
  addEmployee:(state, data) => state.employees.unshift(data)
};

  • Note: Dummy Rest API Create endpoint has an issue of cross-origin. So here we implementing in static approach for understanding Vuex.
  • (Line: 21) 'addEmployee' action method committing new employee data to 'addEmployee' method in mutation object using the 'commit' command.
  • (Line: 26) 'addEmployee' mutation method changing the state of the 'employees' object by adding the new employee object at the top of the 'employees' object collection. 'ushift' javascript method is used to add the new employee record at the top.

Create A AddEmployee Vue Component:

Now we are going to create a new Vue component named 'AddEmployee' which contains a simple form for creating new employees by using 'addEmployee' method from the store actions.
src/components/AddEmployee.vue:
<template>
  <div>
    <form>
      <div class="form-row">
        <div class="col">
          <input type="text" class="form-control" placeholder="Name" v-model="employee.name" />
        </div>
        <div class="col">
          <input type="text" class="form-control" placeholder="age" v-model="employee.age" />
        </div>
        <div class="col">
          <input type="text" class="form-control" placeholder="salary" v-model="employee.salary" />
        </div>
        <div class="col">
          <button type="button" class="btn btn-success" @click="save()">Save</button>
        </div>
      </div>
    </form>
  </div>
</template>

<script>
import { mapActions } from "vuex";

export default {
  name: "AddEmployee",
  data: function() {
    return {
      employee: {
        id: 0,
        name: "",
        age: "",
        salary: ""
      }
    };
  },
  methods: {
    ...mapActions(["addEmployee"]),
    save: function() {
      this.addEmployee(this.employee);
      this.resetEmployee();
    },
    resetEmployee: function() {
        this.employee = {
            id:0,
            name: "",
            age: "",
            salary: ""
        };
    }
  }
};
</script>
  • (Line: 27-36) 'data' property of the Vue component contains all the model properties for the data binding.
  • (Line: 38) fetches the store action method
  • (Line: 39-42)The 'save' method gets invoked on clicking the save button on the form.
  • (Line: 43-50) 'resetEmployee' method to reset form with empty fields after saving the item.
Now register the 'AddEmployee' component inside of the 'Employee' component.
src/component/Employee.vue:
<template>
  <div>
    <AddEmployee />
    <br/>
    <div class="row">
      
    </div>
  </div>
</template>

<script>
import AddEmployee  from "./AddEmployee.vue";

export default {
  // code hidden for display purpose
  name: "Employee",
  components: {
    AddEmployee
  },
};
</script>
  • (Line: 18) 'AddEmployee' registered inside of the 'Employee.vue' component
  • (Line: 3) added 'AddEmployee' component HTML tag.
Now run the application and see the output of  newly added item in the list as below:

Here in the image, we can observe that newly added items automatically updated to the list this happens because store getters are assigned to the computed properties of the Vue component.

Update Existing Employees Using Store:

In previous steps fetch and creating operation of employee data done using the store. Now we are going to write the logic for updating the employee data using the store.

src/store/modules/employee.js:
const state = {
  employees: [],
  employeeToUpdate: null,
  operation:"Add"
};
  • In the sample, we are developing we have 2 Vue components like 'Employee' and 'AddEmployee'. The 'Employee' component has a list of employees and the 'AddEmployee' has form fields either to create or update the employee. So on clicking the edit button on the list of an employee on the 'Employee' Vue component needs to pass the data of the employee to be edited to the 'AddEmployee' Vue component. So sharing data between components will be done with the store we are developing here.
  • (Line: 3) 'employeeToUpdate' property of the store state to hold the employee information that will be used to share the data between from 'Employee' component to the 'AddEmployee' component.
  • (Line: 4) 'operation' property of the store state to hold the information of operation like 'Add' or 'Update' using this information 'save' button on the 'AddEmployee' component will execute its tasks conditionally.
src/store/modules/employee.js:
const mutations = {
  setEmployeeToUpdate: (state,data) => {
    state.employeeToUpdate = data.employeeToUpdate;
    state.operation = data.operationName;
    return state;
  },
};
  • 'setEmployeeToUpdate' is a method of store mutations, in this method we are updating the store state object properties like 'employeeToUpdate' and 'operation'. 
  • Mostly methods of mutation take 2 input parameters, a 1st parameter is a state object this parameter is automatically passed by Vuex on invoking the mutations method using the 'commit' command. 2nd parameter like our application input param like data that need to updated in-store, if we have multiple data points to be passed to the mutation function then all those properties will be passed single javascript object literal parameter.
src/store/modules/employee.js:
const actions = {
  setEmployeeToUpdate({ commit },data) {
    commit("setEmployeeToUpdate",data);
  },
};
  • 'setEmployeeToUpdate' in-store actions method, for action method Vuex by default passes an object literal as 1st input parameter to the method in action method if needed and inside of the object literal 'commit' command is defined.
  • The 'commit' command is used to invoke the 'mutation' methods. The 'commit' command takes 2 types of input parameters like 1st parameter is the name of the function of the mutations to be invoked and 2nd parameter is the data that needs to save into the store state.
src/store/modules/employee.js:
const getters = {
  findEmployeeById: (state) =>(id) => {
    var employee = state.employees.filter((e) => {
      if (e.id === id) {
        return e;
      }
    });
    return employee[0];
  }
};
'findEmployeeById' is the property of the getters of the store. Here fetching the employee by id and this employee object will be stored in the state of object property like 'employeeToUpdate'. getters are purely properties but to pass a parameter to the getters its return type needs to function like above code.

src/components/Employee.vue:
<script>
import { mapActions, mapGetters } from "vuex";
export default {
  methods: {
    ...mapActions(["setEmployeeToUpdate"]),
    edit:function(id){
      var employee = this.findEmployeeaById(id);
      this.setEmployeeToUpdate({employeeToUpdate : employee,operationName:"Update"});
    }
  },
  computed: {
    ...mapGetters(["findEmployeeById"])
  },
};
</script>
  • (Line: 5) Using 'mapActions' loaded 'setEmployeeToUpdate' store action in to the Vue components methods.
  • (Line: 12) Using 'mapGettes' loaded 'findEmployeeById' store getter into Vue components computed properties. Getters always assigned to computed properties because they maintain the latest changes or track the latest changes.
  • (Line: 6-9) The 'edit' method gets invoked on the edit button on the employee box with employee id as an input parameter. Uses 'findEmployeeById' action getter to fetch data. Then fetched data is passed to 'setEmployeeToUpdate' action along with additional info like operational(eg: add or update)
src/components/Employee.vue:
<button type="button" class="btn btn-success" @click="edit(emp.id)">Edit</button>
Employee edit button with 'edit' click event with employee id as an input parameter.

src/store/modules/employee.js:
const getters = {
  getOperation: (state) => state.operation,
  getEmployeeToUpdate:(state) => state.employeeToUpdate
};
  • 'getOperation', 'getEmployeeToUpdate' are store getters. These values are set in the 'Employee' Vue component and these getters will be used in the AddEmployee Vue component. 
  • 'getOperation' getter fetches the value of operation property its value more likely either add or update that defines employee creation or update functionality. 'getEmployeeToUpdate' getter fetches the employee data that need to be updated.
src/components/AddEmployee.vue:
<script>
import {  mapGetters } from "vuex";

export default {
  name: "AddEmployee",
  data: function() {
    return {
      employee: {
        id: 0,
        name: "",
        age: "",
        salary: ""
      }
    };
  },
  computed: {
    ...mapGetters(["getOperation", "getEmployeeToUpdate"])
  },
  watch: {
    getEmployeeToUpdate: function() {
      if (this.getOperation && this.getOperation.toLowerCase() === "update") {
        this.employeeToUpdate();
      } else {
        this.resetEmployee();
      }
    }
  },
  methods: {
    employeeToUpdate: function() {
      if (this.getEmployeeToUpdate) {
        this.employee.name = this.getEmployeeToUpdate.employee_name;
        this.employee.age = this.getEmployeeToUpdate.employee_age;
        this.employee.salary = this.getEmployeeToUpdate.employee_salary;
        this.employee.id = this.getEmployeeToUpdate.id;
      }
    },
    resetEmployee: function() {
      this.employee = {
        id: 0,
        name: "",
        age: "",
        salary: ""
      };
    }
  }
};
</script>
  • (Line: 17) 'mapGetters' load the 'getOperation', 'getEmployeeToUpdate' into component computed properties. On assigning getters in computed props they will become the computed property of the Vue component.
  • (Line: 19) Vue component Watch object is to observe the changes of the data in computed properties
  • (Line: 20-26) 'getEmployeeToUpdate' property changes are watched to update the employee data in the form. 'getOperation' returns 'Update' value then form act as updating form or on returning 'Add' form act as employee creator.
src/store/module/employee.js:
const actions = {
  async updateEmployee({commit}, data){
    // Note:-
    // Dummy Rest API Example create API returning returning cross-orgin issue
    // so i'm explaining by mocking data here

    // const response = await axios.put(`http://dummy.restapiexample.com/update/${data.id}`, data);
    //   commit('addEmployee', response.data);
    const updateEmp = {
      id: data.id,
      employee_name: data.name,
      employee_salary: data.salary,
      employee_age: data.age,
      profile_image: "",
    };
    commit('updatedEmployee',updateEmp)
  }
};
The 'Update' action method is used to update the rest API to save the updated employee on the server. But our dummy rest API returning a cross-origin issue so we are implementing a static way to understand the Vuex. Finally calling mutation function 'updatedEmployee' using the 'commit' command along with bypassing the updated employee data.

src/store/modules/employee.js:
const mutations = {
  updatedEmployee:(state,data) => {
    var employees = state.employees.filter((e) => {
      if (e.id !== data.id) {
        return e;
      }
    });
    employees.unshift(data);
    state.employees = employees;
    return state;
  }
};
Here removing the old object and assigning the newly updated object at the top of the list of store state objects.

src/components/AddEmployee.vue:
export default {

  methods: {
    ...mapActions(["addEmployee","updateEmployee","setEmployeeToUpdate"]),
    save: function() {
      if (this.getOperation.toLowerCase() === "add") {
        this.addEmployee(this.employee);
      }else{
        this.updateEmployee(this.employee);
      }
      this.setEmployeeToUpdate({ employeeToUpdate: null, operationName: "Add" });
      this.resetEmployee();
    },
  }
}
  • The 'save' method is update to do 2 different tasks like creating employee or updating employee based on the 'getOperation' value.
  • (Line: 11) After successful create or update the value of 'operationName' reset back to 'Add'.
Now the full implementation of the update employee-store looks as below:
src/store/modules/employee.js:
import axios from "axios";

const state = {
  employees: [],
  employeeToUpdate: null,
  operation:"Add"
};

const getters = {
  allEmployees: (state) => state.employees,
  findEmployeeById: (state) =>(id) => {
    var employee = state.employees.filter((e) => {
      if (e.id === id) {
        return e;
      }
    });
    return employee[0];
  },
  getOperation: (state) => state.operation,
  getEmployeeToUpdate:(state) => state.employeeToUpdate
};

const actions = {
  async fetchEmployees({ commit }) {
    const response = await axios.get(
      "http://dummy.restapiexample.com/api/v1/employees"
    );
    commit("setEmployees", response.data.data);
  },
  async addEmployee({ commit }, newEmployee) {
    // Note:-
    // Dummy Rest API Example create API returning returning cross-orgin issue
    // so i'm explaining by mocking data here

    //   const response = await axios.post("http://dummy.restapiexample.com/create", newEmployee);
    //   commit('addEmployee', response.data);

    const mapNewEmployee = {
      id: 0,
      employee_name: newEmployee.name,
      employee_salary: newEmployee.salary,
      employee_age: newEmployee.age,
      profile_image: "",
    };
    commit("addEmployee", mapNewEmployee);
  },
  setEmployeeToUpdate({ commit },data) {
    commit("setEmployeeToUpdate",data);
  },
  async updateEmployee({commit}, data){
    // Note:-
    // Dummy Rest API Example create API returning returning cross-orgin issue
    // so i'm explaining by mocking data here

    // const response = await axios.put(`http://dummy.restapiexample.com/update/${data.id}`, data);
    //   commit('addEmployee', response.data);
    const updateEmp = {
      id: data.id,
      employee_name: data.name,
      employee_salary: data.salary,
      employee_age: data.age,
      profile_image: "",
    };
    commit('updatedEmployee',updateEmp)
  }
};

const mutations = {
  setEmployees: (state, data) => {
    state.employees = data;
  },
  addEmployee: (state, data) => state.employees.unshift(data),
  setEmployeeToUpdate: (state,data) => {
    state.employeeToUpdate = data.employeeToUpdate;
    state.operation = data.operationName;
    return state;
  },
  updatedEmployee:(state,data) => {
    var employees = state.employees.filter((e) => {
      if (e.id !== data.id) {
        return e;
      }
    });
    employees.unshift(data);
    state.employees = employees;
    return state;
  }
};

export default {
  state,
  getters,
  actions,
  mutations,
};
src/components/Employee.vue:
<template>
  <div>
    <AddEmployee />
    <br/>
    <div class="row">
      <div class="card" style="width: 18rem;" v-for="emp in allEmployees" v-bind:key="emp.id">
        <div class="card-header">{{emp.employee_name}}</div>
        <ul class="list-group list-group-flush">
          <li class="list-group-item">Salary: {{emp.employee_salary}}</li>
          <li class="list-group-item">Age: {{emp.employee_age}}</li>
        </ul>
        <div>
          <button type="button" class="btn btn-success" @click="edit(emp.id)">Edit</button>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import { mapActions, mapGetters } from "vuex";
import AddEmployee  from "./AddEmployee.vue";

export default {
  name: "Employee",
  components: {
    AddEmployee
  },
  methods: {
    ...mapActions(["fetchEmployees", "setEmployeeToUpdate"]),
    edit:function(id){
      var employee = this.findEmployeeById(id);
      this.setEmployeeToUpdate({employeeToUpdate : employee,operationName:"Update"});
    }
  },
  computed: {
    ...mapGetters(["allEmployees","findEmployeeById"])
  },
  created() {
    this.fetchEmployees();
  }
};
</script>  
src/components/AddEmployee.vue:
<template>
  <div>
    <form>
      <div class="form-row">
        <div class="col">
          <input type="text" class="form-control" placeholder="Name" v-model="employee.name" />
        </div>
        <div class="col">
          <input type="text" class="form-control" placeholder="age" v-model="employee.age" />
        </div>
        <div class="col">
          <input type="text" class="form-control" placeholder="salary" v-model="employee.salary" />
        </div>
        <div class="col">
          <button type="button" class="btn btn-success" @click="save()">Save</button>
        </div>
      </div>
    </form>
  </div>
</template>

<script>
import { mapActions, mapGetters } from "vuex";

export default {
  name: "AddEmployee",
  data: function() {
    return {
      employee: {
        id: 0,
        name: "",
        age: "",
        salary: ""
      }
    };
  },
  computed: {
    ...mapGetters(["getOperation", "getEmployeeToUpdate"])
  },
  watch: {
    getEmployeeToUpdate: function() {
      if (this.getOperation && this.getOperation.toLowerCase() === "update") {
        this.employeeToUpdate();
      } else {
        this.resetEmployee();
      }
    }
  },
  methods: {
    ...mapActions(["addEmployee","updateEmployee","setEmployeeToUpdate"]),
    save: function() {
      if (this.getOperation.toLowerCase() === "add") {
        this.addEmployee(this.employee);
      }else{
        this.updateEmployee(this.employee);
      }
      this.setEmployeeToUpdate({ employeeToUpdate: null, operationName: "Add" });
      this.resetEmployee();
    },
    employeeToUpdate: function() {
      if (this.getEmployeeToUpdate) {
        this.employee.name = this.getEmployeeToUpdate.employee_name;
        this.employee.age = this.getEmployeeToUpdate.employee_age;
        this.employee.salary = this.getEmployeeToUpdate.employee_salary;
        this.employee.id = this.getEmployeeToUpdate.id;
      }
    },
    resetEmployee: function() {
      this.employee = {
        id: 0,
        name: "",
        age: "",
        salary: ""
      };
    }
  }
};
</script>
Now run the application and click on any employee item to edit then output shows below.

Edit employee info as below:

Now save the edited information and output shows as below:

Delete Operation With Store:

The final crud operation we are going to do with our sample is to delete employees.
src/store/module/employee.js:
const actions = {
  async deleteEmployee({commit}, id){
    // Note:-
    // Dummy Rest API Example delete API returning returning cross-orgin issue
    // so i'm explaining by mocking data here
    // const response = await axios.delete(`http://dummy.restapiexample.com/v1/delete/${data.id}`)
    commit('deleteEmployee', id);
  }
};

const mutations = {
  deleteEmployee:(state, id) =>{
    var employees = state.employees.filter((e) => {
      if (e.id !== id) {
        return e;
      }
    });
    state.employees = employees;
    return state;
  }
};
  • (Line: 2-8) 'deleteEmploye' action method call the rest API to delete the employee. Here our Dummy Rest API returning cross-origin issue, so we are implementing the process in a static way to understand the delete operation in the store. The 'commit' command is used to call 'deleteEmployee' mutation method with id passing as the parameter.
  • (Line: 12-20) 'deleteEmployee' mutation method changes the state of the store object by removing the employee matches with the input parameter id.
src/components/Employee.vue:
<template>
  <div>
    <AddEmployee />
    <br />
    <div class="row">
      <div class="card" style="width: 18rem;" v-for="emp in allEmployees" v-bind:key="emp.id">
        
        <div>
          <button type="button" class="btn btn-danger" @click="deleteEmp(emp.id)">Edit</button>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
// some code hidden for displya purpose
import { mapActions, mapGetters } from "vuex";
import AddEmployee from "./AddEmployee.vue";

export default {
  methods: {
    ...mapActions(['deleteEmployee']),
    deleteEmp: function(id) {
      this.deleteEmployee(id);
    }
  }
};
</script>
  • (Line: 9) 'delete' button added in Employee.vue component and to it clicks the event assign 'deleteEmp' method by passing id as the input parameter to it.
  • (Line: 23) 'mapAction' loads store 'deleteEmployee' action method.
  • (Line: 24-26) 'deleteEmp' method that's triggered on clicking the 'Delete' button.

Support Me!
Buy Me A Coffee PayPal Me

Wrapping Up:

Hopefully, I think this article delivered some useful information about Vuex Store Management implementation. I love to have your feedback, suggestions, and better techniques in the comment section below.

Refer:

Follow Me:

Comments

Popular posts from this blog

Angular 14 Reactive Forms Example

In this article, we will explore the Angular(14) reactive forms with an example. Reactive Forms: Angular reactive forms support model-driven techniques to handle the form's input values. The reactive forms state is immutable, any form filed change creates a new state for the form. Reactive forms are built around observable streams, where form inputs and values are provided as streams of input values, which can be accessed synchronously. Some key notations that involve in reactive forms are like: FormControl - each input element in the form is 'FormControl'. The 'FormControl' tracks the value and validation status of form fields. FormGroup - Track the value and validate the state of the group of 'FormControl'. FormBuilder - Angular service which can be used to create the 'FormGroup' or FormControl instance quickly. Form Array - That can hold infinite form control, this helps to create dynamic forms. Create An Angular(14) Application: Let'

.NET 7 Web API CRUD Using Entity Framework Core

In this article, we are going to implement a sample .NET 7 Web API CRUD using the Entity Framework Core. Web API: Web API is a framework for building HTTP services that can be accessed from any client like browser, mobile devices, and desktop apps. In simple terminology API(Application Programming Interface) means an interface module that contains programming functions that can be requested via HTTP calls either to fetch or update data for their respective clients. Some of the Key Characteristics of API: Supports HTTP verbs like 'GET', 'POST', 'PUT', 'DELETE', etc. Supports default responses like 'XML' and 'JSON'. Also can define custom responses. Supports self-hosting or individual hosting, so that all different kinds of apps can consume it. Authentication and Authorization are easy to implement. The ideal platform to build the REST full services. Install The SQL Server And SQL Management Studio: Let's install the SQL server on our l

ReactJS(v18) JWT Authentication Using HTTP Only Cookie

In this article, we will implement the ReactJS application authentication using the HTTP-only cookie. HTTP Only Cookie: In a SPA(Single Page Application) Authentication JWT token either can be stored in browser 'LocalStorage' or in 'Cookie'. Storing the JWT token inside of the cookie then the cookie should be HTTP Only. The HTTP-ONly cookie nature is that it will be only accessible by the server application. Client apps like javascript-based apps can't access the HTTP-Only cookie. So if we use the authentication with HTTP-only JWT cookie then we no need to implement the custom logic like adding authorization header or storing token data, etc at our client application. Because once the user authenticated cookie will be automatically sent to the server by the browser on every API call. Authentication API: To authenticate our client application with JWT HTTP-only cookie, I developed a NetJS(which is a node) Mock API. Check the GitHub link and read the document on G

.NET6 Web API CRUD Operation With Entity Framework Core

In this article, we are going to do a small demo on AspNetCore 6 Web API CRUD operations. What Is Web API: Web API is a framework for building HTTP services that can be accessed from any client like browser, mobile devices, desktop apps. In simple terminology API(Application Programming Interface) means an interface module that contains a programming function that can be requested via HTTP calls to save or fetch the data for their respective clients. Some of the key characteristics of API: Supports HTTP verbs like 'GET', 'POST', 'PUT', 'DELETE', etc. Supports default responses like 'XML' and 'JSON'. Also can define custom responses. Supports self-hosting or individual hosting, so that all different kinds of apps can consume it. Authentication and Authorization are easy to implement. The ideal platform to build REST full services. Create A .NET6 Web API Application: Let's create a .Net6 Web API sample application to accomplish our

Angular 14 State Management CRUD Example With NgRx(14)

In this article, we are going to implement the Angular(14) state management CRUD example with NgRx(14) NgRx Store For State Management: In an angular application to share consistent data between multiple components, we use NgRx state management. Using NgRx state helps to avoid unwanted API calls, easy to maintain consistent data, etc. The main building blocks for the NgRx store are: Actions - NgRx actions represents event to trigger the reducers to save the data into the stores. Reducer - Reducer's pure function, which is used to create a new state on data change. Store - The store is the model or entity that holds the data. Selector - Selector to fetch the slices of data from the store to angular components. Effects - Effects deals with external network calls like API. The effect gets executed based the action performed Ngrx State Management flow: The angular component needs data for binding.  So angular component calls an action that is responsible for invoking the API call.  Aft

Angular 14 Crud Example

In this article, we will implement CRUD operation in the Angular 14 application. Angular: Angular is a framework that can be used to build a single-page application. Angular applications are built with components that make our code simple and clean. Angular components compose of 3 files like TypeScript File(*.ts), Html File(*.html), CSS File(*.cs) Components typescript file and HTML file support 2-way binding which means data flow is bi-directional Component typescript file listens for all HTML events from the HTML file. Create Angular(14) Application: Let's create an Angular(14) application to begin our sample. Make sure to install the Angular CLI tool into our local machine because it provides easy CLI commands to play with the angular application. Command To Install Angular CLI npm install -g @angular/cli Run the below command to create the angular application. Command To Create Angular Application ng new name_of_your_app Note: While creating the app, you will see a noti

Unit Testing Asp.NetCore Web API Using xUnit[.NET6]

In this article, we are going to write test cases to an Asp.NetCore Web API(.NET6) application using the xUnit. xUnit For .NET: The xUnit for .Net is a free, open-source, community-focused unit testing tool for .NET applications. By default .Net also provides a xUnit project template to implement test cases. Unit test cases build upon the 'AAA' formula that means 'Arrange', 'Act' and 'Assert' Arrange - Declaring variables, objects, instantiating mocks, etc. Act - Calling or invoking the method that needs to be tested. Assert - The assert ensures that code behaves as expected means yielding expected output. Create An API And Unit Test Projects: Let's create a .Net6 Web API and xUnit sample applications to accomplish our demo. We can use either Visual Studio 2022 or Visual Studio Code(using .NET CLI commands) to create any.Net6 application. For this demo, I'm using the 'Visual Studio Code'(using the .NET CLI command) editor. Create a fo

Part-1 Angular JWT Authentication Using HTTP Only Cookie[Angular V13]

In this article, we are going to implement a sample angular application authentication using HTTP only cookie that contains a JWT token. HTTP Only JWT Cookie: In a SPA(Single Page Application) Authentication JWT token either can be stored in browser 'LocalStorage' or in 'Cookie'. Storing JWT token inside of the cookie then the cookie should be HTTP Only. The HTTP-Only cookie nature is that it will be only accessible by the server application. Client apps like javascript-based apps can't access the HTTP-Only cookie. So if we use authentication with HTTP only JWT cookie then we no need to implement custom logic like adding authorization header or storing token data, etc at our client application. Because once the user authenticated cookie will be automatically sent to the server by the browser on every API call. Authentication API: To implement JWT cookie authentication we need to set up an API. For that, I had created a mock authentication API(Using the NestJS Se

ReactJS(v18) Authentication With JWT AccessToken And Refresh Token

In this article, we are going to do ReactJS(v18) application authentication using the JWT Access Token and Refresh Token. JSON Web Token(JWT): JSON Web Token is a digitally signed and secured token for user validation. The JWT is constructed with 3 important parts: Header Payload Signature Create ReactJS Application: Let's create a ReactJS application to accomplish our demo. npx create-react-app name-of-your-app Configure React Bootstrap Library: Let's install the React Bootstrap library npm install react-bootstrap bootstrap Now add the bootstrap CSS reference in 'index.js'. src/index.js: import 'bootstrap/dist/css/bootstrap.min.css' Create A React Component 'Layout': Let's add a React component like 'Layout' in 'components/shared' folders(new folders). src/components/shared/Layout.js: import Navbar from "react-bootstrap/Navbar"; import { Container } from "react-bootstrap"; import Nav from "react-boot

A Small Guide On NestJS Queues

NestJS Application Queues helps to deal with application scaling and performance challenges. When To Use Queues?: API request that mostly involves in time taking operations like CPU bound operation, doing them synchronously which will result in thread blocking. So to avoid these issues, it is an appropriate way to make the CPU-bound operation separate background job.  In nestjs one of the best solutions for these kinds of tasks is to implement the Queues. For queueing mechanism in the nestjs application most recommended library is '@nestjs/bull'(Bull is nodejs queue library). The 'Bull' depends on Redis cache for data storage like a job. So in this queueing technique, we will create services like 'Producer' and 'Consumer'. The 'Producer' is used to push our jobs into the Redis stores. The consumer will read those jobs(eg: CPU Bound Operations) and process them. So by using this queues technique user requests processed very fastly because actually