Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Components and How They Interact in Vue and Vuex

DZone's Guide to

Components and How They Interact in Vue and Vuex

A discussion of how components share data between themselves on a large scale, with sample code to make this work in a Vue/Vuex application .

· Web Dev Zone ·
Free Resource

Deploying code to production can be filled with uncertainty. Reduce the risks, and deploy earlier and more often. Download this free guide to learn more. Brought to you in partnership with Rollbar.

Vue, being a progressive framework, is similar to Angular in terms of syntax. In order to understand what components are in Vue and where Vuex comes into the picture, first, we will go through how Vue provides the ability to share data between components.

What Is a Component and Why Do We Need to Share the Data Between Components?

If you are familiar with Angular directives, then it's just like a simple directive wherein we can write our own logic, provide a pattern (template), and call that component (rather than registering the component to the root instance).

Normal interaction between parent and child component

Example :

//Button directive component

Vue.component('button-directive', {
  data: function () {
    return {
    counterValue: 0
    }
  }
  template: '<span>-Button Counter-</span><button v-on:click="counterValue++">{{ count }}</button>'
});

<div id="directive">
<button-directive></button-directive>
</div>

In the above example, button-directive is a component which includes the logic for incrementing the button counter value as well as the template which will actually render the button. These components can be shared with other components when declared at the top level. To know more about components, visit Vue's component documentation. 

The above example shows a single component, but what if there are multiple components with parent and child components sharing the same instance with each other? Sharing between the components (child component and parent component) occurs using various techniques.

1. Props and Events

Props allow you to pass any data type to a child component and allow you to control what sort of data your component receives. This allows a child component to update whenever the parent's data changes. For more information, visit Vue's props documentation. Events are a way of passing the updated information from the child component to the parent component. Events provide a way to inform your parent components of changes in children.

Example: 

<my-component @eventExample="parentHandler"></my-component>

Here my component is a child component with eventExample which will trigger any changes (internally, it uses -  v-on:eventExample ).

An event can be fired in a similar format:

export default {
  methods: {
    fireEvent() {
      this.$emit('eventExample', eventValueOne);
    }
  }
}

Both props and events can be used together with v-modal for two way binding where a change in the input value will call the triggerEvent method.

Example:

<template>
  <div>
  <input type="text" :value="value" @input="triggerEvent"/>
  </div>
</template>

<script>
  export default {
    props: {
    value: String
    },
    methods: {
      triggerEvent(event) {
      this.$emit('input', event.target.value);
      }
    }
  }
</script>

2. Provide/Inject

This allows for the selective exposition of data or methods from an ancestor component to all of its descendants. While provide/inject is not itself reactive, it can be used to pass reactive objects.

Example: Consider two components and those two components sharing. 

const Provider = {
    provide: {
        foo: 'bar'
    },
    template: `<div><slot><slot></div>`
}

const Child = {
    inject: ['foo'],
    template: `<div>{{ foo }} injected. <slot><slot></div>`,
}

new Vue({
    el: '#app',
    components: {
        Child,
        Provider
    }
})

Where Vuex Comes Into the Picture?

As discussed above, we can share instances between two components or, let's say, three components; the problem comes in when one gets into a scenario where one component is shared between two or three components, or even more. Let's say there is a large scale application, which has hundreds of components in it, and one component has a prop that needs to be shared between 50 others; won't that be a problematic issue to maintain the state of that component? In order to handle that, Vuex maintains the state and any changes in the state are handled using mutation, and the mutation can be called using commit.

Vuex, in short, reactively updates any components that are reading data from the store.

  • Actions - Where the state receives the go-ahead values to change the state.

  • Mutation - Where the actual state changes.

Consider the following example. 

Note: In order to initialize store, I'm creating a new instance of Vues.Store.

/* Store where the state is initialized and the values are mutated depending upon the values */

var stateManager = new Vuex.Store {
  state: {
      state1: '', // Initialize the state1
      state2: ''  // Initialize the state2
  }

  actions:{
      // API's can be called here and then accordingly can be passed for mutation
  },

  mutations: {
    changeStateOne(state, payload) {
      state.state1 += payload; // Recieved the payload from the action at the bottom
    },
    changeStateTwo(state, payload) {
      state.state2 += payload; // Recieved the payload from the action at the bottom.
    }
  }
}

// Component one
const componentOne = {
  template: `<div class="componentOne">{{ stateManagerComponent }}</div>`,
  computed: {
    stateManagerComponent() {
      return {
          stateManager.state.state1
          stateManager.state.state2
      }
    }
  }

}


// Component Two
const componentTwo = {
    template: `<div class="componentTwo">{{ stastateManagerComponentteManagerComponent }}</div>`,
    computed: {
        stateManagerComponent() {
            return {
                stateManager.state.state1
                stateManager.state.state2
            }
        }
    }
}



new Vue({
    el: '#app-container',
    components: {
        componentOne,
        componentTwo
    }
    methods: {
        increaseStatesValue() {
            stateManager.commit('changeStateOne', 1); // Action with value one that is sent to the store
            stateManager.commit('changeStateTwo', 2); // Action with value two that is sent to the store
        }
    }
})

  // Thus resulting to a shared state between two components.
<div id="app-container">
<div class="componentOne">{{ stateManagerComponent }}</div>
<div class="componentTwo">{{ stateManagerComponent }}</div>
</div>

In the above example, we see two components sharing the same state between each other wherein the components share the same state with each other and the values get appended in both the components through one single store (in the above example case it is stateManager which is a store of states).

Note on Actions: In the above example, tge Action is the increaseStatesValue() function which is providing the payload to the changeStateOne and changeStateTwo functions in the mutation part.

The above example of Vuex can be mapped in the below diagram.

Image title

Architecture wise, Vuex uses flux as it's method. To learn more about flux, check flux patterns' docs.

I hope this article provides some idea as to why Vuex is used in Vue applications and how it provides smooth communication between two components and promotes ease of change in values between the states.

Deploying code to production can be filled with uncertainty. Reduce the risks, and deploy earlier and more often. Download this free guide to learn more. Brought to you in partnership with Rollbar.

Topics:
vue framework ,vuex ,components ,web dev

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}