Comunicación de Componentes Profundos en Vue.js con Provide/Inject
Clase 20 de 23 • Curso de Vue.js: Introducción y Fundamentos
Contenido del curso
Clase 20 de 23 • Curso de Vue.js: Introducción y Fundamentos
Contenido del curso
Javier Andrés Moreno Tocarruncho
Cristhian De la Cruz
Angel Fernando Quiroz Campos
Brayhan Andres Jaramillo Castaño
José Reinaldo Duque Serna
Christian Barrionuevo
Uriel Solis Salinas
Kevin Acevedo
José Gersain Osorio Morales
Manuel Guzmán
Luis Diego Aguilar Ruiz
Diana Martinez
Angel Fernando Quiroz Campos
Jorge Bou-saad
Edwin Jesús
Carlos Rodríguez
Diana Martinez
Diana Martinez
Juan Guillermo Perez Cardozo
Nicolas Velasquez Lopez
Ramiro Godoy
Rubén Orozco
Gaston Emmanuel Alanis
Manuel Guzmán
Jeronimo celis rodriguez
Diana Martinez
Juan Hernandez
Diana Martinez
Hola, en el minuto 7:28 se corta el video donde va a escribir el from, le estuve intentando para saber cuál sería, ya que ella menciona que es de donde va a provenir el contenido que quiero que aparezca. Lo hice de esta manera por si alguno tiene curiosidad o desea corregirme si no es así. Saludos!
app.component("v-third", { inject:{ otherText: { from : this.provide } }, template: `<h5>{{ otherText }}</h5>` })
Pero muestra error compañero.
Lo correcto es from: 'clave_de_provide
https://vuejs.org/guide/components/provide-inject.html#inject
app.component("tercero", { //inject: ["otroTexto"], inject: { textNew: { from: "otroTexto", }, }, template: ` <div>{{textNew}}</div> `, });
Para utilizar alias de inyección se puede usar el siguiente formato de objeto: text2 es el alias y otravariable es la variable que viene del provide.
inject: { text2: { from: 'otravariable' } },
Muy claro explico el tema la profe, no terminaba de entender el provide /Inject y ahora si.
NOTAS
Componente profundo →Es cuando un componente no es directamente hijo de un elemento padre.
.
Por ejemplo, en este DOM tenemos el componente que provee los datos (<Root>) hasta el inicio de la aplicación, luego existen componentes que son sus hijos directos (<Header>, <Main>, <Footer>) y luego existen otros componentes que son hijos directos de sus hijos (<DeepChild>).
.
Provide e Inject.
.
Ejemplo en código:
const app = Vue.createApp({ data() { return { text: 'Hola mundo desde el padre', }; }, // provide es un método que permite compartir datos entre componentes profundos (hijos de hijos). provide: { otroText: 'Hola mundo desde el proveedor', }, template: ` <div>{{ text }}</div> <segundo></segundo> `, }); app.component('segundo', { template: ` <terver /> `, }); app.component('terver', { // inject es un método que permite recibir datos de un componente padre. inject: ['otroText'], template: ` <div>{{ otroText }}</div> `, }); const vm = app.mount('#app');
Asi queda con la configuarcion en formato JSON utilizando el atributo 'from':
inject: { otroTexto: { from: "otroTexto", },
¿Y si quiero modificar el valor de la variable propagada por provide-inject? se tendría que emitir el evento?
No, normalmente no se usa emit para esto.
La forma más limpia y estándar de permitir que los componentes descendientes modifiquen el valor de la variable es que el componente ancestro (provider) no solo provea la variable, sino también una función o método que se encargue de la modificación.
Quisiera preguntar, si quisiera pasarle los datos de un nieto a un ancentro, como seria? Tendria que pasarlos como si fuesen de padre a hijo?
Puedes usar provide inject también, pero haciendo que el proveedor permita la reactividad
El término técnico es "prop drilling" https://www.geeksforgeeks.org/what-is-prop-drilling-and-how-to-avoid-it/
Super interesante. Yo trabaje muchisimo como Vue 2. Desde el 2018 hasta el 2020. Despues cambie a ReactJs porque me toco trabajar con eso y en este 2022 volvi a Angular otra vez. En aquel tiempo cuando trabajaba con Vue, me hubiera servido muchisimo este concepto de Provide-Inject...es muy util porque no tienes que estar pasando props de manera "callback hell", sino que al proveerlo en el componente padre, tienes acceso en todos sus hijos. Normalmente esto se resuelve con el patron Redux, de hecho la unica libreria que me gusto usar de Redux, fue precisamente Vuex...es un amor. En Angular y React, eso es mas complicado (en Angular es super complicado el tema de Redux). Que grande el equipo de Vue, como que volvere a trabajar con Vue.
Hoy en día es mucho más fácil entender esta parte de provide / inject:
Componente que provee:
<!-- inside provider component --> <script setup> import { provide, ref } from 'vue' const location = ref('North Pole') function updateLocation() { location.value = 'South Pole' } provide('location', { location, updateLocation }) </script>
Componente que inyecta:
<!-- in injector component --> <script setup> import { inject } from 'vue' const { location, updateLocation } = inject('location') </script> <template> <button @click="updateLocation">{{ location }}</button> </template> </script>
La documentación me dice que no es reactivo cuano usamos en provide el this.text, y que debemos usar una función computada que aparece aqui: https://vuejs.org/guide/components/provide-inject.html#working-with-reactivity
.
¿Cómo hago para importar esa función computed() mediante el cdn?
Como la misma documentación de Vue recomienda, es mejor utilizar Options API cuándo queremos usar Vue sin build tools, por ejemplo, cuándo queremos usar solo CDN, esa es una buena estrategia para comenzar o para aplicaciones dónde solo se vaya a utilizar poco y como una librería externa.
Por otro lado Composition API es para cuándo queremos usar Vue cómo un framework, en conjunto con los Single File Components y un build system, cómo webpack (Vue CLI) o Vite.
En otras palabras, si estás usando el CDN, tocaría usar Options API, y no usarías computed cómo función, sino como un JSON con funciones (cómo en el primer curso).
Eso está en "Which to chose?" en la documentación: https://vuejs.org/guide/introduction.html#which-to-choose
Usar Composition API vía CDN es posible pero no recomendable.
la parte del inject como objecto json seria asi:
inject: { otroTexto: { from: "otroTexto", default: "valor default cuando viene vacio" }, // .....de mas codigo }
Notas de la clase
Un componente profundo no es hijo directamente del componente que provee los datos, es decir hay uno a más entre este y el padre principal. Propongo otra forma de escribir el ejemplo de hoy:
const app = Vue.createApp({ data(){ return{ text: "Hola Vue" } }, provide(){ return{ otroTexto: this.text } }, m template:` <p>Padre: {{text}}</p> <v-primerHijo/> ` }) app.component("v-primerHijo",{ inject: ["otroTexto"], template:` <p>Primer hijo: {{otroTexto}}</p> <v-tercer/> ` } ) app.component("v-tercer",{ inject: ["otroTexto"], template:` <div>segundo hijo: {{otroTexto}}</div> ` } ) const vm =app.mount("#app") console.log(vm)
Todos los demás apuntes en mi github
Algo pasó en el min 7:30
Dejo mi aporte; para que funcione la reactividad al componente "profundo", se debe usar la función computed de vue, de la forma como estabamos trabajando no se puden hacer importaciones, se debe usar la sistaxis de modulos ecmascript, en el código funciona, aun que sale un warning
quizas para mayor comprencion pondria en comentarios cual es padre cual es hijo y demas
No sé si ya lo han dicho, pero un ejemplo claro y muy útil para ilustrar provide/inject sería la gestión del estado global de un tema de la aplicación, como theme: "dark" o theme: "light".
Este patrón (provide en un componente ancestro y inject en cualquier componente descendiente) permite que el valor de la variable theme (o la función para cambiarlo) se comparta directamente con cualquier componente hijo o nieto que lo necesite, sin tener que pasarlo manualmente como una prop a través de todos los niveles intermedios de la jerarquía de componentes.
Esto resuelve el problema del "prop drilling" (perforación de propiedades), que es cuando tienes que "perforar" o pasar props innecesarias a través de componentes que no las utilizan, solo para que lleguen a un componente descendiente que sí las requiere. Con provide/inject, se establece un canal directo de comunicación y estado entre el ancestro y cualquier descendiente.
Me sale este error en consola:
Uncaught TypeError: Reflect.ownKeys called on non-object at Reflect.ownKeys (<anonymous>) at applyOptions (vue@next:4975:19) at finishComponentSetup (vue@next:8744:11) at setupStatefulComponent (vue@next:8661:11) at setupComponent (vue@next:8583:13) at mountComponent (vue@next:6945:15) at processComponent (vue@next:6920:19) at patch (vue@next:6522:23) at render (vue@next:7680:15) at mount (vue@next:5926:27)
saben por qué pueda ser?
¿Haciendo esta clase?, ¿te indica la línea del error?
A nivel de rendimiento en un ejemplo si tienes una variable user que tiene un objeto con valores de usuario etc, seria mas eficiente propagarlo con provide-inject o usar un plugin como vuex y tenerlo separado en el state?
Lo ideal es depender lo menos posible de plugins adicionales como manejo de estado, si puedes usar provide-inject y tu componente sigue siendo limpio y reutilizable, eso está muy bien.
Incluso en Vue3 puedes utilizar Composables, un tipo de módulos que puede servir para manejar el estado con herramientas del core de Vue, sin recurrir a una librería adicional.
Por supuesto, el usar una librería como Vuex o Pinia puede tener muchos beneficios en proyectos más grande, sobre todo en código limpio y conciso, mantenible.