13 Ways to Pass Data Between Components in Vue 3
This article comprehensively outlines thirteen distinct methods for component communication in Vue 3, covering parent‑to‑child props, child‑to‑parent emits, sibling communication via mitt, $attrs, refs, v‑model, provide/inject, router parameters, Vuex, Pinia, browser storage, window object, and globalProperties, with concise code examples for each.
Introduction
Vue 3 has been stable for a long time. This article lists thirteen ways to pass data between components, using the most concise <script setup> syntax for each method.
1. Parent to Child (props)
Parent component binds a variable with a colon, child receives it via defineProps .
<template>
<child :name="name"></child>
</template>
<script setup>
import { ref } from 'vue'
import child from './child.vue'
const name = ref('天天鸭')
</script>Child component:
<template>
<div>{{ props.name }}</div>
</template>
<script setup>
import { defineProps } from 'vue'
const props = defineProps({
name: {
type: String,
default: '',
},
})
</script>2. Child to Parent (emit)
Child registers an event with defineEmits and triggers it, passing data to the parent.
<template>
<div></div>
</template>
<script setup>
import { ref, defineEmits } from 'vue'
const name = ref('天天鸭')
const emits = defineEmits(['addEvent'])
const handleSubmit = () => {
emits('addEvent', name.value)
}
</script>Parent component listens to the event:
<template>
<child @addEvent="handle"></child>
</template>
<script setup>
import { ref } from 'vue'
import child from './child.vue'
const handle = value => {
console.log(value) // '天天鸭'
}
</script>3. Sibling Communication (mitt)
Vue 3 uses the mitt library as an event bus for sibling components.
npm install --save mittGlobal registration in main.js :
import mitt from "mitt"
const app = createApp(App)
app.config.globalProperties.$bus = new mitt()Emitter component:
<script setup>
import mitt from 'mitt'
const emitter = mitt()
emitter.emit('custom-event', 'payload')
</script>Listener component:
<script setup>
import mitt from 'mitt'
const emitter = mitt()
emitter.on('custom-event', payload => {
console.log(payload)
})
</script>4. $attrs (un‑declared props)
$attrs receives attributes that are not defined in props . Use useAttrs() to access them.
<template>
<child :name="'天天鸭'" data="PC9527"/>
</template>
<script setup>
import child from './child.vue'
</script> <template>
<div>{{ props.name }}</div>
</template>
<script setup>
import { defineProps, useAttrs } from 'vue'
const props = defineProps({
name: { type: String }
})
const myattrs = useAttrs()
console.log(myattrs) // { data: 'PC9527' }
</script>5. Refs
Parent assigns a ref to the child component; the child must expose properties or methods with defineExpose .
<template>
<child ref="myref"></child>
<button @click="myClick">Click</button>
</template>
<script setup>
import child from "./child.vue"
import { ref } from "vue"
const myref = ref(null)
const myClick = () => {
console.log(myref.value.name)
myref.value.chileMethod()
}
</script> <template>
<div></div>
</template>
<script setup>
import { defineExpose, ref } from "vue"
const chileMethod = () => {
console.log("我是方法")
}
const name = ref('天天鸭')
defineExpose({ name, chileMethod })
</script>6. v‑model
v‑model is syntactic sugar for a prop plus an update: event.
<child v-model:title="title" />
<child :title="title" @update:title="title = $event" />Parent usage:
<template>
<child v-model:name="name" v-model:num="num"></child>
</template>
<script setup>
import child from "./child.vue"
import { ref } from "vue"
const name = ref("天天鸭")
const num = ref("2222")
</script>Child triggers updates with emit :
<template>
<button @click="myClick">Click</button>
</template>
<script setup>
import { defineEmits } from "vue"
const emit = defineEmits(["name", "num"])
const myClick = () => {
emit("update:name", "改个新名字")
emit("update:num", "换个新号码")
}
</script>v‑model Extension (defineModel)
In Vue 3.4+, defineModel() provides a macro for two‑way binding without explicit props or emits.
<template>
<button @click="handleClickCancel">Cancel</button>
</template>
<script setup>
import { defineModel } from 'vue'
const model = defineModel() // or defineModel({ type: Boolean })
const handleClickCancel = () => {
model.value = false
}
</script>7. provide / inject
Allows data to be passed through any number of component layers.
<template>
<div></div>
</template>
<script setup>
import { ref, provide } from 'vue'
const name = ref('天天鸭')
provide('name', name.value)
</script> <template>
<div>{{ name }}</div>
</template>
<script setup>
import { inject } from 'vue'
const name = inject('name')
</script>8. Router Parameters
Data can be passed via query , params (deprecated), or state .
// query
const query = { id: 9527, name: '天天鸭' }
router.push({ path: '/user', query })
const route = useRoute()
console.log(route.query) // params (removed in Vue Router 4.1.4)
router.push({ name: 'test', params: { name: '天天鸭' } })
const route = useRoute()
console.log(route.params) // state
const state = { name: '天天鸭' }
router.push({ path: '/user', state })
console.log(history?.state?.name)9. Vuex
State management using Vuex (see related article for comparison with Pinia).
10. Pinia
State management using Pinia (see related article for comparison with Vuex).
11. Browser Storage
Use localStorage for persistent data and sessionStorage for temporary data.
// Store data
localStorage.setItem('key', 'value');
sessionStorage.setItem('key', 'value');
// Retrieve data
const valLocal = localStorage.getItem('key');
const valSession = sessionStorage.getItem('key');
// Remove data
localStorage.removeItem('key');
sessionStorage.removeItem('key');
// Clear all
localStorage.clear();
sessionStorage.clear();12. Global Window Object
Directly attach properties to window , but this is not recommended for large projects.
window.duname = '天天鸭'
window.duObj = { test: '看看对象' }
console.log(window.duname) // 天天鸭
console.log(window.duObj) // {test: '看看对象'}13. app.config.globalProperties
Vue 3 replaces Vue.prototype with app.config.globalProperties for adding global properties.
import { createApp } from 'vue'
const app = createApp(App)
app.config.globalProperties.msg = 'hello' import { getCurrentInstance } from "vue";
const { proxy } = getCurrentInstance()
console.log(proxy.msg) // helloConclusion
This note serves as a personal reference for Vue 3 component communication. Feel free to point out any mistakes or omissions, and consider giving a like if you found it helpful.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.