New component communication methods
Review of Basic Component Communication Methods
In Vue.js, traditional component communication methods mainly include props and custom events. Parent components pass data to child components via props, while child components pass data to parent components by triggering events with $emit
.
// Parent component
<template>
<ChildComponent :message="parentMessage" @update="handleUpdate" />
</template>
<script>
export default {
data() {
return {
parentMessage: 'Hello from parent'
}
},
methods: {
handleUpdate(newMessage) {
this.parentMessage = newMessage
}
}
}
</script>
// Child component
<template>
<div>
<p>{{ message }}</p>
<button @click="sendMessage">Send Message</button>
</div>
</template>
<script>
export default {
props: ['message'],
methods: {
sendMessage() {
this.$emit('update', 'New message from child')
}
}
}
</script>
Advanced Usage of provide/inject
provide/inject is an API added in Vue 2.2.0, primarily used for high-level component/library development. It allows ancestor components to inject dependencies into all their descendants, regardless of the depth of the component hierarchy.
// Ancestor component
export default {
provide() {
return {
theme: {
color: 'blue',
darkMode: true
}
}
}
}
// Descendant component
export default {
inject: ['theme'],
created() {
console.log(this.theme.color) // "blue"
}
}
In Vue 3, provide/inject can be combined with the Composition API:
// Ancestor component
import { provide, ref } from 'vue'
export default {
setup() {
const theme = ref({
color: 'blue',
darkMode: true
})
provide('theme', theme)
return {
theme
}
}
}
// Descendant component
import { inject } from 'vue'
export default {
setup() {
const theme = inject('theme')
return {
theme
}
}
}
Alternatives to Event Bus
In Vue 2, the Event Bus was a common method for cross-component communication:
// eventBus.js
import Vue from 'vue'
export const EventBus = new Vue()
// Component A
EventBus.$emit('message', 'Hello from A')
// Component B
EventBus.$on('message', (msg) => {
console.log(msg) // "Hello from A"
})
In Vue 3, since methods like $on
and $off
have been removed, third-party libraries such as mitt or tiny-emitter are recommended:
// eventBus.js
import mitt from 'mitt'
export const emitter = mitt()
// Component A
emitter.emit('message', 'Hello from A')
// Component B
emitter.on('message', (msg) => {
console.log(msg) // "Hello from A"
})
State Management with Vuex
For large-scale applications, Vuex provides a centralized state management solution:
// store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++
}
},
actions: {
incrementAsync({ commit }) {
setTimeout(() => {
commit('increment')
}, 1000)
}
}
})
// Usage in components
export default {
computed: {
count() {
return this.$store.state.count
}
},
methods: {
increment() {
this.$store.commit('increment')
},
incrementAsync() {
this.$store.dispatch('incrementAsync')
}
}
}
New Approaches with Composition API
Vue 3's Composition API introduces new patterns for component communication. Through the setup()
function and ref
/reactive
, state can be shared more flexibly:
// useCounter.js
import { ref } from 'vue'
export function useCounter() {
const count = ref(0)
function increment() {
count.value++
}
return {
count,
increment
}
}
// Component A
import { useCounter } from './useCounter'
export default {
setup() {
const { count, increment } = useCounter()
return {
count,
increment
}
}
}
// Component B
import { useCounter } from './useCounter'
export default {
setup() {
const { count } = useCounter()
return {
count
}
}
}
Cross-Component Rendering with Teleport
Vue 3's Teleport component, while primarily used for controlling DOM rendering positions, can also be used for special communication scenarios:
// ParentComponent.vue
<template>
<div>
<ChildComponent />
<Teleport to="#modal-container">
<Modal v-if="showModal" @close="showModal = false" />
</Teleport>
</div>
</template>
<script>
import { ref } from 'vue'
import Modal from './Modal.vue'
export default {
components: { Modal },
setup() {
const showModal = ref(false)
return {
showModal
}
}
}
</script>
Communication Techniques with Custom Directives
Custom directives can also be used for inter-component communication, especially in scenarios requiring direct DOM manipulation:
// v-communication.js
export default {
mounted(el, binding) {
el.addEventListener('click', () => {
binding.instance.$emit('directive-click', binding.value)
})
}
}
// Component using the directive
<template>
<button v-communication="message">Click me</button>
</template>
<script>
export default {
data() {
return {
message: 'Hello from directive'
}
},
created() {
this.$on('directive-click', (msg) => {
console.log(msg) // "Hello from directive"
})
}
}
</script>
Lightweight Reactive Storage Solution
For medium-sized applications that don't require Vuex's complex features, a simple global state can be created using reactive:
// store.js
import { reactive } from 'vue'
export const store = reactive({
state: {
user: null,
settings: {}
},
setUser(user) {
this.state.user = user
}
})
// Usage in components
import { store } from './store'
export default {
setup() {
return {
store
}
}
}
Symbol-Based provide/inject
To avoid naming conflicts, Symbols can be used as keys for provide/inject:
// keys.js
export const THEME_KEY = Symbol('theme')
// Ancestor component
import { THEME_KEY } from './keys'
import { provide, ref } from 'vue'
export default {
setup() {
const theme = ref('dark')
provide(THEME_KEY, theme)
}
}
// Descendant component
import { THEME_KEY } from './keys'
import { inject } from 'vue'
export default {
setup() {
const theme = inject(THEME_KEY)
return {
theme
}
}
}
State Sharing Based on Effect Scope
Vue 3.2 introduced Effect Scope, which allows better management of side effects in composable functions:
// sharedState.js
import { effectScope, ref, computed } from 'vue'
let state
export function useSharedState() {
if (!state) {
state = effectScope().run(() => {
const count = ref(0)
const double = computed(() => count.value * 2)
function increment() {
count.value++
}
return {
count,
double,
increment
}
})
}
return state
}
// Usage in components
import { useSharedState } from './sharedState'
export default {
setup() {
const { count, double, increment } = useSharedState()
return {
count,
double,
increment
}
}
}
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:TypeScript支持增强
下一篇:静态节点提升