Skip to main content

Command Palette

Search for a command to run...

Deep Dive into Vue.js Component Communication Methods

Updated
5 min read
Deep Dive into Vue.js Component Communication Methods

Vue.js component communication is achieved through several methods, each suited to specific use cases. Below is a comprehensive overview of these methods, including code examples and their characteristics.

Props

  • Direction: Parent to Child

  • Purpose: Allows a parent component to pass data to a child component via attributes.

  • Characteristics:

    • Read-Only: Props are immutable by default in the child component.

    • Validation: Props can have defined validation rules.

    • Dynamic: Props can update with changes in the parent component’s state.

Parent Component (Parent.vue)

<template>
  <div>
    <ChildComponent :message="parentMessage" />
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  },
  data() {
    return {
      parentMessage: 'Hello from Parent'
    };
  }
};
</script>

Child Component (ChildComponent.vue)

<template>
  <div>
    <p>{{ message }}</p>
  </div>
</template>

<script>
export default {
  props: {
    message: String
  }
};
</script>

$emit (Events)

  • Direction: Child to Parent

  • Purpose: Enables a child component to notify the parent by triggering custom events.

  • Characteristics:

    • Data Transmission: Events can carry data payloads.

    • Multiple Events: A child can emit multiple distinct events.

Child Component (ChildComponent.vue)

<template>
  <button @click="notifyParent">Notify Parent</button>
</template>

<script>
export default {
  methods: {
    notifyParent() {
      this.$emit('child-event', 'Hello from Child');
    }
  }
};
</script>

Parent Component (Parent.vue)

<template>
  <ChildComponent @child-event="handleChildEvent" />
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  },
  methods: {
    handleChildEvent(data) {
      console.log('Received data from child:', data);
    }
  }
};
</script>

Vuex

  • Global State Management

  • Purpose: Manages application-wide state accessible by any component.

  • Characteristics:

    • State: Stores global state data.

    • Mutations: Synchronous operations, the only way to modify state.

    • Actions: Handle asynchronous operations, dispatching mutations.

    • Getters: Computed properties based on state, cached for efficiency.

    • Modules: Split state management into modules for large applications.

Setting Up Vuex Store (store.js)

import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    sharedCounter: 0
  },
  mutations: {
    increment(state) {
      state.sharedCounter++;
    }
  },
  actions: {
    incrementAsync({ commit }) {
      setTimeout(() => {
        commit('increment');
      }, 1000);
    }
  },
  getters: {
    getCounter: state => state.sharedCounter
  }
});

Main Application (main.js)

Ensure the application integrates the Vuex Store:

import Vue from 'vue';
import App from './App.vue';
import store from './store';

new Vue({
  store,
  render: h => h(App)
}).$mount('#app');

Using Vuex in Components (ComponentUsingVuex.vue)

<template>
  <div>
    <p>Counter: {{ counter }}</p>
    <button @click="increment">Increment</button>
    <button @click="incrementAsync">Increment Async</button>
  </div>
</template>

<script>
export default {
  computed: {
    counter() {
      return this.$store.getters.getCounter;
    }
  },
  methods: {
    increment() {
      this.$store.commit('increment');
    },
    incrementAsync() {
      this.$store.dispatch('incrementAsync');
    }
  }
};
</script>

Provide/Inject

  • Cross-Level Communication

  • Purpose: Allows an ancestor component to provide data that descendants can inject, bypassing intermediate parent-child hierarchies.

  • Characteristics:

    • Hierarchy-Independent: Works across multiple levels but may increase code coupling.

    • Limited Use: Best suited for library or framework-level data passing, not general component communication.

Ancestor Component (AncestorComponent.vue)

<template>
  <div>
    <ChildComponent />
  </div>
</template>

<script>
export default {
  provide() {
    return {
      ancestorValue: 'Value from Ancestor'
    };
  }
};
</script>

Descendant Component (DescendantComponent.vue)

<template>
  <div>
    <p>Value from Ancestor: {{ ancestorValue }}</p>
  </div>
</template>

<script>
export default {
  inject: ['ancestorValue'],
  mounted() {
    console.log('Injected value:', this.ancestorValue);
  }
};
</script>

Ref and v-model

  • Direct Reference

  • Purpose: Allows a parent to directly access a child component instance or enable two-way data binding.

  • Characteristics:

    • Refs: Used to access child component instances or DOM elements for direct manipulation.

    • v-model: Facilitates two-way data binding, commonly used with form elements or custom components.

Parent Component (ParentComponent.vue)

<template>
  <ChildComponent ref="childRef" v-model="parentValue" />
  <button @click="logChildRef">Log Child Ref</button>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  },
  data() {
    return {
      parentValue: 'Initial Value'
    };
  },
  methods: {
    logChildRef() {
      console.log(this.$refs.childRef);
    }
  }
};
</script>

Child Component (ChildComponent.vue)

<template>
  <input :value="value" @input="$emit('input', $event.target.value)" />
</template>

<script>
export default {
  props: ['value']
};
</script>

Custom Events

  • Event-Based Communication

  • Purpose: Enables non-standard communication between components via custom events.

  • Characteristics:

    • Flexible: Can be triggered and listened to between any components.

    • Complex Interactions: Suitable for specific interactions or intricate component communication.

Child Component (ChildComponent.vue)

<template>
  <button @click="customEvent">Send Custom Event</button>
</template>

<script>
export default {
  methods: {
    customEvent() {
      this.$emit('custom-event', 'Data to send');
    }
  }
};
</script>

Parent Component (ParentComponent.vue)

<template>
  <ChildComponent @custom-event="handleCustomEvent" />
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  },
  methods: {
    handleCustomEvent(data) {
      console.log('Received custom event data:', data);
    }
  }
};
</script>

Slots

  • Content Distribution

  • Purpose: Allows a parent component to insert content into specific areas of a child component.

  • Characteristics:

    • Default Slot: The default content area in a child component.

    • Named Slots: Multiple slots can be defined, with the parent specifying content placement.

    • Scoped Slots: The parent can access child component data to customize slot content.

Parent Component (ParentComponent.vue)

<template>
  <WrapperComponent>
    <h1 slot="header">Custom Header</h1>
    <p slot="body">Custom Body Content</p>
  </WrapperComponent>
</template>

<script>
import WrapperComponent from './WrapperComponent.vue';

export default {
  components: {
    WrapperComponent
  }
};
</script>

Wrapper Component (WrapperComponent.vue)

<template>
  <div>
    <slot name="header"></slot>
    <div class="content">
      <slot name="body"></slot>
    </div>
  </div>
</template>

Composition API

  • New Feature

  • Purpose: Introduced in Vue 3, it provides better logic and data organization within components.

  • Characteristics:

    • setup() Function: Runs at the start of the component lifecycle, accessing props and lifecycle hooks.

    • ref and reactive: Manage reactive data.

    • provide and inject: Enhanced implementations for flexible cross-component data passing.

Parent Component (ParentComponent.vue)

<template>
  <ChildComponent :count="count" @updateCount="updateCount" />
</template>

<script>
import { ref, onMounted } from 'vue';
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  },
  setup() {
    const count = ref(0);

    function updateCount(newCount) {
      count.value = newCount;
    }

    onMounted(() => {
      console.log('Initial count:', count.value);
    });

    return {
      count,
      updateCount
    };
  }
};
</script>

Child Component (ChildComponent.vue)

<template>
  <button @click="increment">Increment</button>
</template>

<script>
import { ref } from 'vue';

export default {
  props: ['count'],
  setup(props, { emit }) {
    const count = ref(props.count);

    function increment() {
      count.value++;
      emit('updateCount', count.value);
    }

    return {
      count,
      increment
    };
  }
};
</script>

Web Development

Part 9 of 46

The content covers the three basics of HTML/CSS/JS/TS, modular development, mainstream frameworks (Vue, React, Angular, Svelte), build tools, browser plug-in development, Node.js backend practice, Next.js/Nest.js and other popular technologies.

Up next

Webpack Performance Tuning-Comprehensive Optimization from Loaders to Plugins

Webpack is a module bundler that transforms project resources (JavaScript, CSS, images, etc.) into one or more browser-compatible output files. Optimizing Webpack performance focuses on reducing build time, minimizing output file size, and improving ...

More from this blog

T

Tianya School Technical Articles

48 posts

Welcome to our tech publication, where we share high-quality content on full-stack development, frontend/backend/web3/AI, and engineering best practices.