Home > Software design >  Vuex/Redux store pattern - sharing single source of data in parent and child components that require
Vuex/Redux store pattern - sharing single source of data in parent and child components that require

Time:01-12

I understand the benefits of using a store pattern and having a single source of truth for data shared across components in an application, and making API calls in a store action that gets called by components rather than making separate requests in every component that requires the data.

It's my understanding that if this data needs to change in some way, depending on the component using the data, this data can be updated by calling a store action with the appropriate filters/args, and updating the global store var accordingly.

However, I am struggling to understand how to solve the issue whereby a parent component requires one version of this data, and a child of that component requires another.

Consider the following example:

In an API, there exists a GET method on an endpoint to return all people. A flag can be passed to return people who are off sick:

GET: api/people returns ['John Smith', 'Joe Bloggs', 'Jane Doe']

GET: api/people?isOffSick=true returns ['Jane Doe']

A parent component in the front end application requires the unfiltered data, but a child component requires the filtered data. For arguments sake, the API does not return the isOffSick boolean in the response, so 2 separate requests need to be made.

Consider the following example in Vue.js:

// store.js

export const store = createStore({
  state: {
    people: []
  },
  actions: {
    fetchPeople(filters) {
      // ...
      const res = api.get('/people'   queryString);
      commit('setPeople', res.data);
    }
  },
  mutations: {
    setPeople(state, people) {
      state.people = people;
    }
  }
});
// parent.vue - requires ALL people (NO filters/args passed to API)

export default {
  mounted() {
    this.setPeople();
  },
  computed: {
    ...mapState([
      'people'
    ])
  },
  methods: {
    ...mapActions(['setPeople']),
  }
}
// child.vue - requires only people who are off sick (filters/args passed to API)

export default {
  mounted() {
    this.setPeople({ isOffSick: true });
  },
  computed: {
    ...mapState([
      'people'
    ])
  },
  methods: {
    ...mapActions(['setPeople']),
  }
}

The parent component sets the store var with the data it requires, and then the child overwrites that store var with the data it requires.

Obviously the shared store var is not compatible with both components.

What is the preferred solution to this problem for a store pattern? Storing separate state inside the child component seems to violate the single source of truth for the data, which is partly the reason for using a store pattern in the first place.

Edit:

My question is pertaining to the architecture of the store pattern, rather than asking for a solution to this specific example. I appreciate that the API response in this example does not provide enough information to filter the global store of people, i.e. using a getter, for use in the child component.

What I am asking is: where is an appropriate place to store this second set of people if I wanted to stay true to a store focused design pattern?

It seems wrong somehow to create another store variable to hold the data just for the child component, yet it also seems counter-intuitive to store the second set of data in the child component's state, as that would not be in line with a store pattern approach and keeping components "dumb".

If there were numerous places that required variations on the people data that could only be created by a separate API call, there would either be a) lots of store variables for each "variation" of the data, or b) separate API calls and state in each of these components.

CodePudding user response:

Thanks to tao I've found what I'm looking for:

The best approach would be to return the isOffSick property in the API response, then filtering the single list of people (e.g. using a store getter), thus having a single source of truth for all people in the store and preventing the need for another API request.

If that was not possible, it would make sense to add a secondary store variable for isOffSick people, to be consumed by the child component.

  • Related