Using Vuex with multiple child components

So i’m building an app and decided to implement Vuex. The app contains many different components and some of them are related to each other like:

|-- app
|- – maincomponent
|- – -- child 1
|- – -- – child 2
|- – -- – -- child 3

So the case is:
When I want to retrieve some information of the store and show in it child 3 I have the following options:

  1. I can retrieve the data of the store in maincomponent and pass it to child 3.
  2. I will tell child component 3 to retrieve the data from the store and show it.

Is there a best practise?

The next thing i want to accomplish
There are many input fields in component 3 and the data that was entered should be commited to the store. My code in component 3 looks like this:

<template>
<div>
<input type="text" v-model="firstname" />
<input type="text" v-model="birthname" />
</div>
</template>
Vue.extend({
  props: {
    contact: {
      type: Object as () => ContactModel,
      required: true,
    },
  },
  computed: {
    firstname: {
      get(): string | null {
        return this.contact.firstname
      },
      set(value: string) {
        // this.contact.firstname = value; // this will trigger a store violation and i know why

      },
    },
...

What is the best way to set firstname and all other props to make a commit to the store.

  1. I can create for every field a new data property to track local changes in my component (child 3) and commit it at once to the store. But i will get a lot of new variables that should be added to the component like:
 data(): { newFirstname: string | null } {
    return {
      newFirstname: null,
    };
  },

Then i can emit an event with all the newVariables that should be committed to the store.

  1. I can emit the value in every computed setter, but:
    But every property requires a mutation. And if a want to delegate the commit throught the maincomponent i have to emit an event in child 3.

Thanks for helping!

Hi @forens7,

You can create computer properties to get the date from the store and update it whenever it changes in your child 3 component. For example you can do this by using getters and setters

computed: {
    first_name: {
      get() {
        return this.$store.getters["user/getUserFirstName"];
      },
      set(value) {
        this.$store
          .dispatch("user/setFirstName", value)
          .then(() => {})
          .catch(() => {});
      }
    },

In the example above, I assume that you have a module named user with a getter called getUserFirstName and an action called setFirstName. Then if you use v-model to bind the computer property in both ways

<input type="text" v-model="first_name" />

whenever you type a new name, Vue will detect the change and will update your store accordingly. However, be aware that by using this method the store will be updated multiple times. For example whenever you type a new letter the store will be updated

1 Like

Relative to your first question, I recommend using Vuex so that any component can access the data store directly, instead of only a mainComponent managing the data and then having to pass props down multiple levels, and process events from descendants.

Relative to the second question, I have used Vuex a few times, having used mutations but not actions.

Ghad’s answer sounds reasonable, but I’m not sure if you need ‘dispatch’ (actions) or could get by with ‘commit’ (mutations), as what you are trying to do doesn’t appear to be asynchronous, but I could be wrong.

Also, instead of using a computed ‘setter’ (which I admit I haven’t had to use), you could add a ‘change’ event handler to the input, and then ‘commit’ (or ‘dispatch’) from the handler. My understanding is that a ‘change’ event is only fired after the input loses focus or the ‘enter’ key is pressed, which would eliminate a store update every time a letter is added to an input.

There is also the option of using ‘v-model.lazy’ on the inputs. See this link.

1 Like

This depends on how re-usable you want/need your components to be. If you need them to be re-usable then props are the way to go, but if you don’t and you have no issue tying it to your store then it makes perfect sense to have that dependency.

My usual approach with forms is to have a controller/manager component which is dependent on the store and handles the bulk of the form logic. I then use small individual form components (inputs, etc.) and pass down props to be handled independently.

Also, as others have said, computed properties are the way to go to wire up your v-models, however this can cause a lot of updates to the store so debouncing the input or using the change event is recommended.

If you’re doing a lot of work with forms and vuex, you may want to look at a helper plugin to help wire up all the fields. There’s a few out there, but this is the first that comes to mind: https://github.com/maoberlehner/vuex-map-fields

Thanks for your answer. I my case i got a matrix of data (50+ fields) that can be changed by the user. So i have to write for every field a lot of code. That can be better right?

The docs tells me there are multiple approaches to set and get the data into the store. Link

I like the v-model way. It feels more robust.

Thanks for answering.

  1. These components dot not have to be very reusable. So its fine to use the store in the component.
  2. I am more familair with Angular and normally I use the formbuilder approach, which make sense.

So the data looks like a big tree with multiple branches and leafs and I want to change one of its leafs and persist the data directly into the store. What should you do?

Situation:

The components that showing the data is almost the same as the data structure.
The data is not presented anywhere else on the screen at the same time.

  1. Is Vuex the way to handle this problem?
  2. Should I try something else?
  3. For every commit to the store I have to find the right branch. So I need some navigating logic to find the right place for every leaf.

Hi @forens7,

I wouldn’t recommend my way for 50+ fields. Yes, computed properties is a good solution but you want to avoid all those updates. Take the best of the 3 answers we have provided you to develop a solution. Use computed properties but do that on the @change event to limit the updates.

I think only you can answer those questions as you know your project best.

I will say though, if you don’t need the form field states to persist (not talking about after a refresh, but if you were to navigate away from the view and then come back. e.g. a shopping cart) then spending the time to wire them to Vuex wouldn’t be a win IMO.

If you do need them to persist but not on each fields input or change event, one approach I have taken when dealing with forms that have many fields is to only commit the changes to Vuex on form submission or on next step in the case of a wizard flow.