SkillByAIOpen interactive version →

Lesson 12 / 25

provide and inject

Passing data deep without prop drilling.

Dependency injection for component trees

Passing a prop through many intermediate components that do not use it is called prop drilling. With provide(key, value) an ancestor makes a value available to all its descendants, and any descendant reads it with inject(key, defaultValue). Providing a ref keeps the link reactive. A good practice is to keep mutations in the provider by also providing an update function, and to wrap values with readonly() when consumers should not change them. With TypeScript, an InjectionKey symbol gives the injected value a type. app.provide makes a value available to the whole app, which is how many plugins work.

Providing a theme

An ancestor provides; a deep child injects.

<!-- App.vue -->
<script setup>
import { ref, provide, readonly } from 'vue'

const theme = ref('light')
function toggleTheme() {
  theme.value = theme.value === 'light' ? 'dark' : 'light'
}
provide('theme', { theme: readonly(theme), toggleTheme })
</script>

<!-- ThemeButton.vue, anywhere below App -->
<script setup>
import { inject } from 'vue'

const { theme, toggleTheme } = inject('theme', {
  theme: 'light',
  toggleTheme: () => {},
})
</script>

<template>
  <button @click="toggleTheme">Theme: {{ theme }}</button>
</template>

Building-wide Wi-Fi

Instead of running a cable through every room (props), the building broadcasts a network (provide) and any device on any floor can connect (inject).

Quick check: What problem does provide/inject mainly solve?

  • Fetching data from a server
  • Prop drilling through components that do not need the data
  • Styling child components
  • Routing between pages
Answer

Prop drilling through components that do not need the data — Ancestors share values with any descendant.