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)
ReactivoSíSíSí
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.