Comunicación padre-hijo con props en Vue

Clase 27 de 53Curso Profesional de Vue.js 2

Resumen

Aprende a conectar componentes en Vue.js con confianza: de padre a hijo usando props reactivas e inmutables, y de hijo a padre con eventos. Verás cómo estructurar un componente de pista musical con Bulma, corregir el binding con v-bind, optimizar rutas con un alias en webpack y mejorar la UX con un loader controlado por v-show.

¿Cómo se comunican los componentes en Vue.js con props y eventos?

La comunicación fluye en dos direcciones, pero con mecanismos distintos.

  • Padre → hijo con props: se envía data por atributos tipo HTML. Son reactivas e inmutables en el hijo. No se deben mutar en el hijo.
  • Hijo → padre con eventos: el hijo emite y el padre escucha. Se verá en la siguiente parte, pero conviene distinguirlo desde ahora.
  • Reactividad: las props se comportan como data, actualizan la vista cuando cambian en el padre.
  • Inmutabilidad en el hijo: preserva el flujo de datos limpio y la coherencia del estado.
  • Binding correcto: usa v-bind o : para pasar valores no literales; sin ello, se envía un string.

Habilidades puestas en práctica: manejo de props, reactividad, inmutabilidad, binding con v-bind, depuración con DevTools de Vue, y lectura de estructuras anidadas que llegan desde una API.

¿Cómo construir y alimentar el componente de track?

Se crea track.vue con el esqueleto de un card de Bulma para mostrar imagen, título, artista y duración. Además, se define la prop track como requerida.

¿Cómo definir las props reactivas?

<script> export default { name: 'PmTrack', props: { track: { type: Object, required: true } } } </script>
  • Clave: la prop pertenece al padre; no se muta en el hijo.

¿Cómo renderizar imágenes, título y artista con v-bind?

<template> <div class="card"> <div class="card-image"> <figure class="image is-1by1"> <img :src="track.album.images[0].url" alt="Álbum"> </figure> </div> <div class="card-content"> <div class="media"> <div class="media-left"> <figure class="image is-48x48"> <img :src="track.album.images[0].url" alt="Álbum"> </figure> </div> <div class="media-content"> <p class="title is-6"><strong>{{ track.name }}</strong></p> <p class="subtitle is-6">{{ track.artists[0].name }}</p> </div> </div> <div class="content"> <small>{{ track.duration_ms }}</small> <nav class="level"> <div class="level-left"> <span class="icon">▶️</span> </div> </nav> </div> </div> </div> </template>
  • Lectura de datos anidados: track.album.images[0].url, track.name, track.artists[0].name, track.duration_ms (en milisegundos).
  • Con DevTools de Vue se detecta rápidamente si se está pasando un string en lugar del objeto.

Uso correcto desde el padre con v-for y v-bind:

<pm-track v-for="t in tracks" :key="t.id" :track="t" />

Si se omite :track="t" y se usa track="t", se pasará el literal "t" y no el objeto.

¿Cómo mejorar la experiencia con alias, responsive y loader?

Se optimiza la importación con alias, se mejora el responsive layout con Bulma y se añade un loader visible solo durante las búsquedas.

¿Cómo importar con alias en webpack?

// webpack.config.js resolve: { alias: { '@': pathResolve('source') } }
  • Permite importar con rutas absolutas: @/components/track.vue.
  • Tras cambiar el config, reinicia el build para aplicar el alias.

¿Cómo mostrar un loader con v-show e isLoading?

loader.vue reutilizable en components/shared.

<template> <div class="container"> <div class="content has-text-centered"> <h1>Cargando...</h1> </div> </div> </template> <style lang="sass"> .content padding: 20px min-height: 40vh </style>

Registro e inserción controlada desde el padre:

<pm-loader v-show="isLoading" /> <section v-show="!isLoading"> <!-- resultados --> </section>
export default { components: { PmLoader }, data () { return { isLoading: false } } // Al iniciar la búsqueda: this.isLoading = true // Al finalizar la búsqueda: this.isLoading = false }
  • v-show es ideal cuando se alterna visibilidad con frecuencia, evita montar/desmontar nodos.
  • El scope de isLoading es del componente padre; los hijos no necesitan conocerlo.

Además, el grid de Bulma mejora la UI en desktop sin perder mobile:

<div class="columns is-multiline"> <div class="column is-one-quarter" v-for="t in tracks" :key="t.id"> <pm-track :track="t" /> </div> </div>
  • is-multiline para que las tarjetas salten a la siguiente fila.
  • is-one-quarter para 4 columnas en pantallas grandes.

Conceptos y keywords trabajados: props, eventos, reactividad, inmutabilidad, v-bind, v-show, scope, DevTools, alias de webpack @, UI con Bulma (card, media, image is-48x48), loader reutilizable en shared, prefijo PM para componentes.

¿Te quedó alguna duda o quieres compartir cómo estructuraste tus props y el loader? Comenta y seguimos la conversación.