SoFunction
Updated on 2025-04-05

Detailed explanation of how to pass values ​​between vue components

Overview

We all know that Vue is a lightweight front-end framework, its core is component development. Vue is composed of components one by one, and componentization is its essence and one of its most powerful functions. The scope of component instances is independent of each other, which means that data between different components cannot be referenced.

However, in the actual project development process, we need to access the data of other components, which leads to the problem of component communication. In vue, the relationship between components is: father and son, brother, and generation. How to implement data transmission for different relationships is what we will talk about next.

1. Parent component passes value to child component

That is, the parent component passes the value to the child component through attributes, and the child component receives it through props.

Bind custom properties in child component tag of parent component

// Parent component<user-detail :myName="name" />
    
export default {
    components: {
        UserDetail
    }
    ......
}

Use props (can be an array or an object) to receive it in the child component. Multiple attributes can be passed.

// Subcomponentsexport default {
    props: ['myName']
}
​
/*
 props: { myName: String } //This way, it will be warned if the type is incorrect.
 props: { myName: [String, Number] } // Multiple possible types
 prosp: { myName: { type: String, requires: true } } //Required string
 props: {
     childMsg: {
         type: Array,
         default: () => []
     }
 } // default specifies the default value
 If props verification fails, a warning will be issued in the console.
 */

The values ​​of the parent component received by the child component are divided into reference type and normal type:

Normal types: String, Number, Boolean, Null

Reference type: array (Array), object (Object)

A one-way data stream based on vue, that is, the data between components is unidirectional. The child components do not allow direct modification of the values ​​transmitted by the parent component, so this operation of directly modifying the values ​​transmitted by the parent component should be avoided, otherwise the console will report an error.

If the value passed in is a simple data type, it can be modified in the child component and will not affect the value from the parent component being called in other sibling components.

The specific operation is to first reassign the passed value to a variable in data, and then change that variable.

// Subcomponentsexport default {
    props: ['myName'],
    data() {
        return {
            name :     // Assign the passed value to a new variable        }
    },
    watch: {
        myName(newVal) {
             = newVal // Listen to the values ​​passed by the parent component, and if changed, change the values ​​inside the child component.        }
    },
    methods: {
        changeName() {  
             = 'Lily'  // What you modify here is only the internal value, so there will be no errors        },
    }
}

Note: If you do not use watch to listen for the myName value passed by the parent component, the name value in the child component will not change with the myName value of the parent component, because name: in data only defines an initial value.

If a value of the type is referenced, when modified in the child component, the parent component's also has been modified because its data is common, and other child components that also reference the value will also be modified. It can be understood that the value passed to the child component by the parent component is equivalent to copying a copy, and the pointer of this copy still points to the one in the parent component, that is, sharing the same reference. So, unless there are special needs, do not modify it easily.

2. The child component passes value to the parent component

1. The child component binds an event and triggers it through this.$emit()

Bind an event in a child component and define a function for this event

// Subcomponents<button @click="changeParentName">Change the parent component'sname</button>
​
export default {
    methods: {
        // Events of subcomponents        changeParentName: function() {
            this.$emit('handleChange', 'Jack') // Trigger the handleChange event in the parent component and pass the Jack            // Note: The event name here must be consistent with the event name bound in the parent component        }
    }
}

Define and bind handleChange events in the parent component

// Parent component<child @handleChange="changeName"></child>
​
methods: {
    changeName(name) {  // The name parameter is the value passed in the child component Jack         = name
    }
}

2. Through the callback function

First define a callback function in the parent component and pass the callback function over

// Parent component<child :callback="callback"></child>
​
methods: {
    callback: function(name) {
         = name
    }
}

Receive in the child component and execute the callback function

// Subcomponents<button @click="callback('Jack')">Change the parent component'sname</button>
​
props: {
    callback: Function,
}

3. Access component instances through $parent / $children or $refs

Both of these are directly obtained component instances, and after use, you can directly call component methods or access data.

// Subcomponentsexport default {
  data () {
    return {
      title: 'Subcomponent'
    }
  },
  methods: {
    sayHello () {
        ('Hello');
    }
  }
}
// Parent component<template>
  <child ref="childRef" />
</template>
​
<script>
  export default {
    created () {
      // Access subcomponents through $ref      (this.$);  // Subcomponents      this.$(); // Hello
      
      // Call child component methods through $children      this.$(); // Hello 
    }
  }
</script>

Note: Component communication in this way cannot be cross-level.

3. Passing values ​​between brother components

1. Or by combining $emit and props

In the parent component, bind the variable to be passed to both the brother components to be passed and define the event

// Parent component<child-a :myName="name" />
<child-b :myName="name" @changeName="editName" />  
    
export default {
    data() {
        return {
            name: 'John'
        }
    },
    components: {
        'child-a': ChildA,
        'child-b': ChildB,
    },
    methods: {
        editName(name) {
             = name
        },
    }
}

Receive variables and binding trigger events in child component B

// child-b component<p>Name:{{ myName }}</p>
<button @click="changeName">修改Name</button>
    
<script>
export default {
    props: ["myName"],
    methods: {
        changeName() {
            this.$emit('changeName', 'Lily')   // Trigger event and pass value        }
    }
}
</script>
// child-a component<p>Name:{{ newName }}</p>
    
<script>
export default {
    props: ["myName"],
    computed: {
        newName() {
            if() { // Determine whether there is a value passed                return 
            }
            return 'John' //The default value without passing value        }
    }
}
</script>

That is: When child component B triggers the parent component's event function editName through $emit(), changing the variable name value of the parent component, the parent component can pass the changed value to child component A through props, thereby realizing data transfer between brother components.

2. Pass an empty vue instance

Create a file and expose a vue instance

import Vue from 'Vue'
export default new Vue()

Import this empty vue instance in the file to be passed, bind the event and trigger the event function through $emit

(You can also introduce the js file globally in the component I usually introduce it in the components I need to use)

<template>
    <div>
        <p>Name: {{ name }}</p>
        <button @click="changeName">修改Name</button>
    </div>
</template>
​
<script>
import { EventBus } from "../"
​
export default {
 data() {
     return {
         name: 'John',
     }
  },
  methods: {
      changeName() {
           = 'Lily'
          EventBus.$emit("editName", ) // Trigger the global event and pass the changed value into the event function      }
    }
}
</script>

The vue instance is also imported in the component that receives the passed value. The callback is listened to by $on. The callback function receives all parameters passed in when the event is triggered.

import { EventBus } from "../"
​
export default {
    data() {
        return {
            name: ''
        }
    },
    created() {
         EventBus.$on('editName', (name) => {
              = name
         })
    }
}

This way of creating an empty vue instance is equivalent to creating an event center or a transit station to pass and receive events. This method is also suitable for communication between any components, including father and son, brother, and cross-level. It is more convenient for projects with simple communication requirements, but for more complex situations or when the project is larger, you can use the more complex state management mode Vuex provided by vue to handle it.

4. Multi-layer parent-child component communication

Sometimes the two components that need to implement communication are not direct parent-child components, but grandfathers and grandsons, or parent-child components that span more levels. In this case, it is impossible to pass parameters upwards from the child components one by one, especially when the component level is deep and there are many nestings, there are many events and attributes that need to be passed, which will cause the code to be confused.

At this time, you need to use a higher-order method provided by vue: provide/inject.

This pair of options needs to be used together to allow an ancestor component to inject a dependency into all its descendants, regardless of the depth of the component hierarchy and always take effect during the time when the upstream and downstream relationship is established.

provide/inject: Simply put, it is to provide variables in the parent component through a provider, and then inject variables in the child component through an inject. No matter how deep the component level is, this variable will always be valid during the life cycle of the parent component's effect.

Parent component:

export default {
  provide: { // Its function is to provide the **name** variable to all its child components.    name: 'Jack'
  }
}

Subcomponents:

export default {
  inject: ['name'], // Injected the name variable provided from the parent component  mounted () {
    ();  // Jack
  }
}

Note: Provide and inject bindings are not responsive. That is, after the name of the parent component changes, the child component will not change accordingly.

If you want to implement provide and inject data responses, there are two ways:

Provide instances of the ancestor component and inject dependencies into the descendant component, so that the properties of the ancestor component can be directly modified in the descendant component. However, this method has a disadvantage that this instance is that many unnecessary things such as props and methods are mounted on this instance.

// Parent component<div>
      <button @click="changeName">Modify your name</button>
      <child-b />
</div>
<script>
    ......
    data() {
        return {
            name: "Jack"
        };
    },
    provide() {
        return {
            parentObj: this //Providing examples of ancestor components        };
    },
    methods: {
        changeName() {
             = 'Lily'
        }
    }
</script>

Values ​​in descendant components:

<template>
<div class="border2">
<P>Name:{{}}</P>
</div>
</template>
<script>
export default {
inject: {
parentObj: {
default: () => ({})
}
} // Or inject: ['parentObj']};
</script>

Note: This method is used more frequently in functional components. Functional components, that is, stateless (no responsive data), no instantiation (no this context), and no lifecycle processing methods internally, so they have high rendering performance and are more suitable for components that rely on external data transmission.

Summarize

Parent-son communication: The parent passes data to the child through props, and the child passes $emit; communicates through $parent / $children; $ref can also access component instances; provide / inject; $attrs / $listeners;

Brothers correspondence: EventBus; Vuex;

Cross-level communication: EventBus; Vuex; provide/inject; $attrs/$listeners;

The above is a detailed explanation of the way to pass values ​​between vue components. For more information about vue, please pay attention to my other related articles!