En Vue,js, provide
e inject
son dos funciones de que permiten compartir datos entre componentes en una jerarquía profunda.
Ya hemos visto que la forma habitual para pasar datos y variables de un componente padre a un componente hijo, es utilizar props.
Sin embargo, si hay múltiples niveles de componentes anidados, pasarlo de un componente a otro, y al otro, y al otro, se puede convertir en un engorro.
A ese problema se le denomina prop drilling, y acaba convirtiéndose en un pequeño dolor de sintaxis.
Para mejorar esto Vue proporciona provide
e inject
, como alternativa al uso de props
para pasar datos entre componentes sin pasar manualmente a través de cada nivel.
¿Qué son provide
e inject
?
Las palabras clave provide
e inject
forman parte de un mecanismo que nos permite compartir datos entre componentes,
- provide: Se usa en un componente padre para proveer datos o métodos que estarán disponibles para todos sus componentes descendientes.
- inject: Se usa en un componente hijo para inyectar los datos o métodos proporcionados por un componente ancestro.
Vamos a verlo con un ejemplo
<template>
<div>
<ChildComponent />
</div>
</template>
<script setup>
import { provide } from 'vue';
import ChildComponent from './ChildComponent.vue';
const message = 'Hola desde el componente padre';
provide('message', message); // Provee el valor 'message'
</script>
<template>
<div>
<p>Mensaje recibido: {{ injectedMessage }}</p>
</div>
</template>
<script setup>
import { inject } from 'vue';
const injectedMessage = inject('message'); // Inyecta el valor 'message'
</script>
En este ejemplo:
- El componente padre (
ParentComponent
) provee un valor (message
) usandoprovide
. - El componente hijo (
ChildComponent
) inyecta el valor usandoinject
y lo muestra en su template.
Valores por defecto en inject
<template>
<div>
<p>Mensaje recibido: {{ injectedMessage }}</p>
</div>
</template>
<script setup>
import { inject } from 'vue';
const injectedMessage = inject('message', 'Valor por defecto'); // Valor por defecto
</script>
En este ejemplo:
- Si el valor
message
no está disponible, se usa el valor por defecto'Valor por defecto'
.
Proveer e inyectar datos reactivos
Los datos proporcionados con provide
pueden ser reactivos, lo que significa que los cambios en los datos se reflejarán automáticamente en los componentes que los inyectan.
<template>
<div>
<ChildComponent />
<button @click="changeMessage">Cambiar mensaje</button>
</div>
</template>
<script setup>
import { provide, ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
const message = ref('Hola desde el componente padre');
provide('message', message); // Provee el valor reactivo 'message'
function changeMessage() {
message.value = '¡Mensaje cambiado!';
}
</script>
<template>
<div>
<p>Mensaje recibido: {{ injectedMessage }}</p>
</div>
</template>
<script setup>
import { inject } from 'vue';
const injectedMessage = inject('message'); // Inyecta el valor reactivo 'message'
</script>
En este ejemplo:
- El componente padre provee un valor reactivo (
message
) usandoprovide
. - El componente hijo inyecta el valor reactivo y lo muestra en su template.
- Cuando el botón en el componente padre cambia el mensaje, el componente hijo se actualiza automáticamente.
Proveer e inyectar métodos
Además de datos, también puedes proveer e inyectar métodos. Esto es útil para compartir funcionalidades entre componentes.
<template>
<div>
<ChildComponent />
</div>
</template>
<script setup>
import { provide } from 'vue';
import ChildComponent from './ChildComponent.vue';
function showAlert() {
alert('¡Este es un método proporcionado por el componente padre!');
}
provide('showAlert', showAlert); // Provee el método 'showAlert'
</script>
<template>
<div>
<button @click="injectedShowAlert">Mostrar alerta</button>
</div>
</template>
<script setup>
import { inject } from 'vue';
const injectedShowAlert = inject('showAlert'); // Inyecta el método 'showAlert'
</script>
En este ejemplo:
- El componente padre provee un método (
showAlert
) usandoprovide
. - El componente hijo inyecta el método y lo usa en un botón.