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.

      Comunicación padre-hijo con props en Vue