Skip to main content

Command Palette

Search for a command to run...

Deep Dive into Vue.js Component Communication Methods

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

I focus on the long-term foundations of computer science, software engineering, and emerging technologies.covering computer science, AI, semiconductors, quantum computing, and future engineering.

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.