Provide / Inject
Esta página asume que ya has leído la sección Fundamentos de Componentes. Léela primero si eres nuevo en los componentes.
Propagación de Props
Normalmente, cuando necesitamos pasar datos del componente padre a un componente hijo, utilizamos props. Sin embargo, imagina el caso en el que tenemos un árbol de componentes grande, y un componente anidado profundamente necesita algo de un componente ancestro distante. Con solo props, tendríamos que pasar la misma prop a través de toda la cadena de padres:

Observa que, aunque el componente <Footer> puede no preocuparse en absoluto por estas props, aún necesita declararlas y pasarlas para que <DeepChild> pueda acceder a ellas. Si hay una cadena de padres más larga, más componentes se verían afectados en el camino. Esto se llama "props drilling" (propagación de props) y definitivamente no es divertido de manejar.
Podemos resolver el "props drilling" con provide e inject. Un componente padre puede actuar como un proveedor de dependencia para todos sus descendientes. Cualquier componente en el árbol descendiente, sin importar cuán profundo esté, puede inyectar dependencias proporcionadas por componentes en su cadena de padres.

Provide
Para proporcionar datos a los descendientes de un componente, utiliza la función provide():
vue
<script setup>
import { provide } from 'vue'
provide(/* clave */ 'message', /* valor */ '¡hola!')
</script>Si no utilizas <script setup>, asegúrate de que provide() se llame sincrónicamente dentro de setup():
js
import { provide } from 'vue'
export default {
setup() {
provide(/* clave */ 'message', /* valor */ '¡hola!')
}
}La función provide() acepta dos argumentos. El primer argumento se llama clave de inyección, que puede ser una cadena de texto o un Symbol. La clave de inyección es utilizada por los componentes descendientes para buscar el valor deseado a inyectar. Un solo componente puede llamar a provide() varias veces con diferentes claves de inyección para proporcionar distintos valores.
El segundo argumento es el valor proporcionado. El valor puede ser de cualquier tipo, incluyendo estado reactivo como refs:
js
import { ref, provide } from 'vue'
const count = ref(0)
provide('key', count)Proporcionar valores reactivos permite a los componentes descendientes que utilizan el valor proporcionado establecer una conexión reactiva con el componente proveedor.
Provide a Nivel de Aplicación
Además de proporcionar datos en un componente, también podemos proporcionar a nivel de aplicación:
js
import { createApp } from 'vue'
const app = createApp({})
app.provide(/* clave */ 'message', /* valor */ '¡hola!')Las provides a nivel de aplicación están disponibles para todos los componentes renderizados en la aplicación. Esto es especialmente útil al escribir plugins, ya que los plugins normalmente no podrían proporcionar valores utilizando componentes.
Inject
Para inyectar datos proporcionados por un componente ancestro, utiliza la función inject():
vue
<script setup>
import { inject } from 'vue'
const message = inject('message')
</script>Si múltiples padres proporcionan datos con la misma clave, inject resolverá el valor del padre más cercano en la cadena de padres del componente.
Si el valor proporcionado es una ref, se inyectará tal cual y no se desenvolverá automáticamente. Esto permite que el componente inyector mantenga la conexión de reactividad con el componente proveedor.
Ejemplo completo de provide + inject con Reactividad
De nuevo, si no utilizas <script setup>, inject() solo debe llamarse sincrónicamente dentro de setup():
js
import { inject } from 'vue'
export default {
setup() {
const message = inject('message')
return { message }
}
}Valores de Inyección por Defecto
Por defecto, inject asume que la clave inyectada se proporciona en algún lugar de la cadena de padres. En el caso de que la clave no se proporcione, habrá una advertencia en tiempo de ejecución.
Si queremos que una propiedad inyectada funcione con proveedores opcionales, necesitamos declarar un valor por defecto, similar a las props:
js
// `value` será "default value" si no se
// proporcionaron datos que coincidieran con "mensaje"
const value = inject('message', 'default value')En algunos casos, el valor por defecto puede necesitar ser creado llamando a una función o instanciando una nueva clase. Para evitar cálculos innecesarios o efectos secundarios en caso de que el valor opcional no se utilice, podemos usar una función de fábrica para crear el valor por defecto:
js
const value = inject('key', () => new ExpensiveClass(), true)El tercer parámetro indica que el valor por defecto debe tratarse como una función de fábrica.
Trabajar con Reactividad
Cuando se utilizan valores provide / inject reactivos, se recomienda mantener cualquier mutación del estado reactivo dentro del proveedor siempre que sea posible. Esto asegura que el estado proporcionado y sus posibles mutaciones estén colocalizados en el mismo componente, facilitando su mantenimiento en el futuro.
Puede haber momentos en los que necesitemos actualizar los datos desde un componente inyector. En tales casos, recomendamos proporcionar una función que sea responsable de mutar el estado:
vue
<!-- componente proveedor interno -->
<script setup>
import { provide, ref } from 'vue'
const location = ref('North Pole')
function updateLocation() {
location.value = 'South Pole'
}
provide('location', {
location,
updateLocation
})
</script>vue
<!-- en el componente inyector -->
<script setup>
import { inject } from 'vue'
const { location, updateLocation } = inject('location')
</script>
<template>
<button @click="updateLocation">{{ location }}</button>
</template>Finalmente, puedes envolver el valor proporcionado con readonly() si quieres asegurarte de que los datos pasados a través de provide no puedan ser mutados por el componente inyector.
vue
<script setup>
import { ref, provide, readonly } from 'vue'
const count = ref(0)
provide('read-only-count', readonly(count))
</script>Trabajar con Symbol Keys
Hasta ahora, hemos estado usando claves de inyección de cadena de texto en los ejemplos. Si estás trabajando en una aplicación grande con muchos proveedores de dependencia, o estás creando componentes que van a ser utilizados por otros desarrolladores, es mejor usar claves de inyección Symbol para evitar posibles colisiones.
Se recomienda exportar los Symbols en un archivo dedicado:
js
export const myInjectionKey = Symbol()js
// en el componente proveedor
import { provide } from 'vue'
import { myInjectionKey } from './keys.js'
provide(myInjectionKey, {
/* datos a proveer */
})js
// en el componente inyector
import { inject } from 'vue'
import { myInjectionKey } from './keys.js'
const injected = inject(myInjectionKey)Ver también: Tipado de Provide / Inject