Master Vue’s Provide/Inject: Simplify Component Communication
This article explains Vue’s provide/inject API, how it enables ancestor components to share data with any descendant, compares it to Vuex for global state, shows practical code examples, discusses limitations and best‑practice guidelines, and demonstrates its use in component libraries like Element UI.
In component‑based development, communication between components is a major pain point. Vue offers many mechanisms such as props/$emit, EventBus, and Vuex, but the provide/inject API is often overlooked.
What Is provide/inject?
Added in Vue 2.2.0, provide allows an ancestor component to supply data or methods, and any descendant can retrieve them with inject, similar to React’s context.
<code>// Parent provides 'foo'
var Provider = {
provide: {
foo: 'bar'
}
}
// Child injects 'foo'
var Child = {
inject: ['foo'],
created () {
console.log(this.foo) // => "bar"
}
}
</code>Using provide/inject for Global State Management
While Vuex is the typical solution for global state, some developers prefer a lighter approach. provide/inject can serve as a simple global store, but the provided values are not reactive unless the object itself is reactive.
<code>// Root component provides a non‑reactive variable
export default {
provide () {
return { text: 'bar' }
}
}
// Descendant injects 'text'
<template>
<div>{{ text }}</div>
</template>
<script>
export default {
inject: ['text'],
created() {
this.text = 'baz' // template still shows 'bar'
}
}
</script>
</code>Because provide does not make its properties reactive, you must supply a reactive object (e.g., the component instance itself) to achieve reactivity.
<code>// Root provides its own instance
export default {
provide () {
return { app: this }
},
data () {
return { text: 'bar' }
}
}
// Descendant injects 'app'
<template>
<div>{{ app.text }}</div>
</template>
<script>
export default {
inject: ['app'],
created() {
this.app.text = 'baz' // template shows 'baz'
}
}
</script>
</code>When to Use Caution
Vue still recommends Vuex because its mutations are traceable, whereas changes to values obtained via provide/inject are uncontrolled and can break the unidirectional data flow principle, leading to tight coupling and unpredictable side effects in collaborative projects.
Two guidelines for using provide/inject as a global store:
Isolate scopes when multiple developers work together.
Prefer one‑time data for global state.
Using provide/inject to Build Components
Element UI’s Button component demonstrates how provide/inject can replace deep prop drilling. By injecting the parent Form and FormItem contexts, the Button can access size settings regardless of nesting depth.
<code>export default {
name: 'ElButton',
// Inject Form and FormItem
inject: {
elForm: { default: '' },
elFormItem: { default: '' }
},
computed: {
_elFormItemSize() {
return (this.elFormItem || {}).elFormItemSize;
},
buttonSize() {
return this.size || this._elFormItemSize || this.$ELEMENT?.size;
}
}
}
</code>Conclusion
Understanding less‑used APIs like provide/inject can reveal powerful patterns that simplify component communication and state sharing, especially in large Vue projects.
Weidian Tech Team
The Weidian Technology Platform is an open hub for consolidating technical knowledge. Guided by a spirit of sharing, we publish diverse tech insights and experiences to grow and look ahead together.
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.