Vue Provide/Inject: Skip Prop Drilling
Vue's provide/inject lets an ancestor component share data directly with any descendant, avoiding the tedious 'prop drilling' chain. Use it for app-wide data like user info or theme settings. The footgun: providing a simple value is not reactive by default.
WHY IT EXISTS When a deeply nested component needs data from a distant ancestor, you're often forced to pass that data down as a prop through every intermediate component. This is called 'prop drilling' and it clutters components that don't care about the data, making the system brittle and hard to refactor.
THE MENTAL MODEL Think of provide/inject as a data wormhole. An ancestor component 'provides' data on a named channel, and any descendant, no matter how deep, can 'inject' that data by tuning into the same channel. This creates a direct link, bypassing all components in between.
HOW IT WORKS An ancestor component uses the provide function or option to register a value under a specific key, which can be a string or a Symbol. For example, in the Composition API: provide('theme', 'dark'). Any descendant component can then use the inject function to retrieve that value: const theme = inject('theme'). The key must match exactly. A single component can provide multiple values using different keys. For data to be reactive across components, you must provide a reactive object, like one created with ref() or reactive(). Providing a static value will not trigger updates in child components if it changes in the parent.
WHEN TO USE IT Use provide/inject for cross-cutting concerns that apply to a whole subtree of components. Good candidates include the current authenticated user object, UI theme settings, or localization functions. It's for data that many components need, but which would be inconvenient to pass down manually.
WHEN NOT TO USE IT Avoid using it for standard parent-to-direct-child communication. Props are more explicit and make data flow easier to trace in simple cases. Overusing provide/inject can obscure your component's dependencies, making it harder to reason about where state comes from, similar to the pitfalls of global variables.
ONE CANONICAL EXAMPLE A root App.vue component might manage a theme state and provide it to the entire application. App.vue would contain: const theme = ref('light'); provide('theme', theme);. A deeply nested <Button.vue> component could then access this without its direct parent knowing: const theme = inject('theme');, and use it to apply a class like :class="theme".
Read the original → vuejs.org
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.