4
votes

I'm currently practicing Vue with Vuex and the REST API architecture (with Django). I wanna retrieve the data from by database and store the data in my global state in order to access it throughout my Vue components. It works fine so far but there is one weird thing I do not understand.

When I start my application I have the homepage where currently nothing is displayed. I click on the menu item "Contacts" and the contacts component loads (router-view) (API GET call is executed) and displays the table of all the created contacts and shows it properly (source of truth is now my global state). I can edit, delete and view a contact.The contacts are now stored in the global state as well.

The problem: Everytime I load the contact component the mounted() lifecycle gets called (which makes sense) and loads the contacts from the API inside the state so the whole lists gets dupblicated over and over. I just want Vue to make a GET request only once and then access the state's data (where to contacts are stored now).

Another scenario is when I update a contact and click back to the contacts menu item the list contains the old contact and the updated one but when I refresh the page it is fine.

Thanks!

MY CODE

state.js

import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

import { apiService } from "../utils/api.service.js";

export const store = new Vuex.Store({
  state: {
    contacts: []
  },
  mutations: {
    initContacts_MU: (state, data) => {
      state.contacts.push(...data);
    },
    updateContact_MU: (state, data) => {
      let getContact = state.contacts.filter(contact => contact.id === data.id);
      let getContactIndex = state.contacts.indexOf(getContact);
      state.contacts.splice(getContactIndex, 1, data);
    },
    deleteContact_MU: (state, data) => {
      let getContact = state.contacts.filter(contact => contact.id === data.id);
      let getContactIndex = state.contacts.indexOf(getContact);
      state.contacts.splice(getContactIndex, 1);
    },
    createContact_MU: (state, data) => {
      state.contacts.unshift(data);
    }
  },
  actions: {
    initContacts_AC({ commit }) {
      let endpoint = "api/contacts/";
      apiService(endpoint).then(data => {
        commit("initContacts_MU", data);
      });
    },
    updateContact_AC({ commit }, contact) {
      let endpoint = "/api/contacts/" + contact.slug + "/";
      apiService(endpoint, "PUT", contact).then(contact => {
        commit("updateContact_MU", contact);
      });
    },
    deleteContact_AC({ commit }, contact) {
      let endpoint = "/api/contacts/" + contact.slug + "/";
      apiService(endpoint, "DELETE", contact).then(contact => {
        commit("deleteContact_MU", contact);
      });
    },
    createContact_AC({ commit }, contact) {
      let endpoint = "/api/contacts/";
      apiService(endpoint, "POST", contact).then(contact => {
        commit("createContact_MU", contact);
      });
    }
  },
  getters: {
    contacts: state => {
      return state.contacts;
    }
  }
});

ContactList.vue

<script>
import Contact from "../../components/Contacts/Contact.vue";

import { mapGetters, mapActions } from "vuex";

export default {
   name: "ContactList",
   components: {
      Contact
   },
   computed: {
      ...mapGetters(["contacts"])
   },
   methods: {
      ...mapActions(["initContacts_AC"])
   },
   mounted() {
      this.initContacts_AC();
   }
};
</script>
1
You have any code to show?Omi in a hellcat
Make your api call from parent component, and update your store. Now add these component which get removed and inserted conditionally by either passing prop or the availability of the required dataSatyam Pathak
Sure, I edited my post.Effection

1 Answers

3
votes

Just check if there're contacts which are already retrieved from backend.

   computed: {
      ...mapGetters(["contacts"])
   },
   methods: {
      ...mapActions(["initContacts_AC"])
   },
   mounted() {
      if (this.contacts && this.contacts.length > 0) return; // already fetched.
      this.initContacts_AC();
   }

EDIT:

updateContact_MU: (state, data) => {
  const contactIndex = state.contacts.findIndex(contact => contact.id === data.id);
  if (contactIndex < 0) return; 
  state.contacts.splice(contactIndex, 1, data);
}