Search code examples
javascriptvue.jsvuex

Vue / Vuex - correct way to create and set store items from main object


I am somewhat new to Vue and trying figure out the correct way to take a "master" store object and then run some functions to strip keys and rename other keys and create an altered version of it and save that to the store as a new store item.

I dispatch a "loadData" action in created() of App.js and then calling a local function 'prepareData' to take the mapState["eventsData"] and manipulate it to create two new store items.

What's happening is the 'master' eventsData object is getting changed by my functions. Also, on the initial page load, this.eventsData (the main object) consoles as the dreaded [__ob__: Observer]. The next page load it has the data because it's getting it from localStorage at that point.

App.js (prepareData() is just a key/value tweaking function).

export default {
  name: "App",
  data() {
    return {
      calendarData: [],
      gridData: [],
    };
  },
  computed: mapState(["eventsData"]),
  created: function () {
    state.commit("initializeStore");
    this.$store.dispatch("loadData"); // this loads then commits "setEventsData"
    this.prepareData();
  },
  methods: {
    prepareData() {
      this.calendarData = this.eventsData.forEach((event, i) => {
        delete event.artist_supporting;
        delete event.genre;
        delete event.venue;
        delete event.venue_city;
        delete event.venue_state;
        delete event.capacity;
        delete event.announce_date;
        delete event.onsale_date;
        delete event.promoter;
        delete event.business_unit;
        delete event.show_type;
        delete event.confirm_date;
        delete event.cancelled_date;
        delete event.status;

        event.venue_id = `event_${i}`;
        event.id = event.venue_id;
        event.title = event.artist_headliner;
        event.startDate = event.event_date;

        delete event.venue_id;
        delete event.artist_headliner;
        delete event.event_date;

        let date = new Date(event.startDate);
        let day = date.getDate();
        let month = date.getMonth() + 1;
        let year = date.getFullYear();
        if (day < 10) {
          day = "0" + day;
        }
        if (month < 10) {
          month = "0" + month;
        }
        event.startDate = year + "-" + month + "-" + day;
      });
      this.gridData = this.eventsData.forEach((event) => {
        let date = new Date(event.event_date);
        console.log(event.event_date);
        let day = date.getDate();
        let month = date.getMonth() + 1;
        let year = date.getFullYear();
        if (day < 10) {
          day = "0" + day;
        }
        if (month < 10) {
          month = "0" + month;
        }
        event.event_date = year + "-" + month + "-" + day;
      });
      state.commit("setCalendarData", this.calendarData);
      state.commit("setGridData", this.gridData);
    },
  },
};

index/store.js

 mutations: {
    initializeStore(state) {
      state.eventsData = JSON.parse(localStorage.getItem("eventsData")) || [];
      state.calendarData = JSON.parse(localStorage.getItem("calendarData")) || [];
      state.gridData = JSON.parse(localStorage.getItem("gridData")) || [];
    },
    setEventsData: (state, data) => {
      state.eventsData = data;
      localStorage.setItem("eventsData", JSON.stringify(data));
    },
    setCalendarData: (state, data) => {
      state.calendarData = data;
      localStorage.setItem("calendarData", JSON.stringify(data));
    },
    setGridData: (state, data) => {
      state.gridData = data;
      localStorage.setItem("gridData", JSON.stringify(data));
    },
  actions: {
    loadData({ commit }) {
      axios
        .get("/data/eventsData.json")
        .then((response) => {
          commit("setEventsData", response.data);
          commit("setLoading", false);
        })
        .catch((error) => {
          console.log(error);
        });
    },
  },

Solution

  • First of all, just a few things to note:

    I dispatch a "loadData" action in created() of App.js and then calling a local function 'prepareData'

    No, you're not. The axios call is asynchronous and you do not wait for it to finish before calling your prepareData() method. If you need proof, clear your localStorage and slow down your network using your browser dev tools. You could fix it like so:

    loadData({ commit }) {
        return axios
            .get("/data/eventsData.json")
            .then((response) => {
                commit("setEventsData", response.data);
                commit("setLoading", false);
            })
            .catch((error) => {
                console.log(error);
            });
    }
    
    this.$store.dispatch("loadData").then(() => {
        this.prepareData();
    });
    

    That being said, I don't thing you should do this in your Vue component. I would suggest moving this method to your store to call it in the then method of your axios call. It would make things way easier if you ever want to refresh your data from another component and it keeps your Vue file smaller.

    Also, I would suggest not using the delete keyword as the would mutate the objects inside the eventsData array as well (same reference). Just re-create an object using the ES6 spread operator syntax.

    And finally, did you consider using a vuex getter instead of storing a modified version of the eventsData array?