Skip to content
← Todas las preguntas
⚡ Intermedio

¿Qué es Provide/Inject?

🧩 Componentes🔗 Composition API🍍 Pinia💉 Provide/Inject

Cuando un componente padre necesita pasar datos a un hijo profundamente anidado, normalmente tendrías que pasar props a través de cada componente intermedio, aunque esos componentes no usen los datos. Esto se llama "prop drilling", y hace el código frágil y difícil de mantener.

provide e inject resuelven esto. Un padre provee datos, y cualquier descendiente, sin importar la profundidad, puede inyectarlos directamente sin que ningún componente intermedio sepa de ellos.

Diagrama de árbol mostrando provide/inject saltando componentes intermedios

Cómo funciona

vue
<!-- GrandParent.vue -->
<script setup lang="ts">
import { provide, ref } from 'vue'

const theme = ref('dark')
provide('theme', theme)
</script>
Open in Vue Playground
vue
<!-- DeeplyNestedChild.vue (cualquier nivel por debajo de GrandParent) -->
<script setup lang="ts">
import { inject } from 'vue'

const theme = inject('theme') // 'dark' — sin props pasadas por componentes intermedios
</script>
Open in Vue Playground

El valor provisto es reactivo. Cuando theme cambia en el padre, cada componente que lo inyectó se actualiza automáticamente.

Inyección tipada con InjectionKey

Las claves de string funcionan pero no ofrecen seguridad de tipos. Usa InjectionKey para provide/inject tipados:

ts
// keys.ts
import type { InjectionKey, Ref } from 'vue'

interface User {
  name: string
  role: string
}

export const UserKey: InjectionKey<Ref<User>> = Symbol('user')
ts
// Provider
import { provide, ref } from 'vue'
import { UserKey } from '@/keys'

const user = ref<User>({ name: 'John', role: 'admin' })
provide(UserKey, user)
ts
// Consumer
import { inject } from 'vue'
import { UserKey } from '@/keys'

const user = inject(UserKey) // Ref<User> | undefined
const userWithDefault = inject(UserKey, ref({ name: 'Guest', role: 'viewer' })) // con valor por defecto

Cuándo usarlo (y cuándo no)

Buenos casos de uso:

  • Tema o configuración regional compartida en toda la app
  • Estado de autenticación/usuario accesible en lo profundo del árbol
  • Contexto de tabla o formulario (un <Table> provee configuración de columnas, el <TableCell> hijo lo inyecta)
  • Funcionalidades tipo plugin (un gestor de toasts, un gestor de modales)

Malos casos de uso:

  • Pasar datos entre componentes hermanos. provide/inject es solo de ancestro a descendiente
  • Reemplazar todas las props con inject. Hace los componentes más difíciles de testear y entender porque sus dependencias son implícitas
  • Estado global que muchos componentes no relacionados leen y escriben. Usa Pinia en su lugar

Provide/Inject vs Props vs Pinia

PropsProvide/InjectPinia
DirecciónPadre → hijo (1 nivel)Ancestro → cualquier descendienteCualquier componente → cualquier componente
ExplícitoSí (visible en la plantilla)No (dependencia implícita)Parcialmente (importar store)
Reactivo
Mejor paraDatos padre-hijo directosContexto de un subárbolEstado global de la app

Ver también: ¿Qué es getCurrentInstance() y por qué deberías evitarlo? · ¿Qué es un composable?

Referencias

Publicado bajo la licencia MIT.