Michael
Michael

Reputation: 6907

Share data between sibling components if data is not already persisted to Vuex?

If I have two sibling components that share the same data and that data is not already persisted to Vuex (e.g. a direct page load to api/v1/calendars/:id, would making a call to that resource within both components be necessary? I have read the following:

Vue components should be as self-contained and isolated as much as possible

If that is true, then requesting the data from Vuex from within both components is correct, but the application would be making two network calls when only one is required if that data is not already available in Vuex.

Ideally I would like to make a single network call for the required resource, then multiple components on that page all share the data within Vuex.

I would be duplicating this code in both components, specifically the created() method.

<script>
import store from '@state/store'
import { calendarComputed } from '@state/helpers'

export default {
  data() {
    return {
      calendar: null,
    }
  },
  computed: {
    ...calendarComputed,
  },
  created() {
    // Are calendars already persisted?
    if (!this.calendars.length) {
      store.dispatch('calendar/getCalendars').then((res) => {
        this.calendar = res.find((calendar) => { if (calendar.id == this.$route.params.id) return calendar })
      })
    } else {
      this.calendar = this.calendars.find((calendar) => { if (calendar.id == this.$route.params.id) return calendar })
    }
  },
}
</script>

Upvotes: 2

Views: 67

Answers (1)

Richard Matsen
Richard Matsen

Reputation: 23533

The simplest way would be to make your components not (explicitly) care about whether the calendars have been fetched.

Simply tell the store to fetch, but the action decides if it actually needs to do so.

Vuex is supposed to be one-way data flow, so status info does not come back from the action to the component, instead the component always just waits for the data to arrive.

To make things reactive, use a combination of computed and getter.

component

created() {
  /* tell the store 'this is what I need' */
  store.dispatch('calendar/getCalendars');
},
...
computed: {
  calendar() {
    /* reactive - initially null, then gets a value when the store is updated */
    return this.$store.getters['calendar/calendarById'](this.$route.params.id)
  },
},

store

getters: {
  calendarById: (state) => {
    /* return a function so that param can be passed from component */
    return (id) => state.calendars ? state.calendars.find(c => c.id === id) : null;
  },
}

actions: {
  getCalendars (store) {
    /* only perform the fetch if the store does not already contain the data */
    if (!store.state.calendars) {
      fetch(calendarsUrl).then(res => store.commit('setCalendars', res); // e.g
    }
  },
}

Upvotes: 1

Related Questions