Introducción

Una de las ventajas de los web components es que se pueden parametrizar, es decir, puedes pasar cierta información a los componentes para que se puedan adaptar dependiendo de las necesidades.

En el primer artículo de Vue (Tutorial básico componentes) ya vimos que las etiquetas HTML no son más que web components ya que tienen vista, estilos y lógica. Sabes que cuando creas un input, por ejemplo, puedes decidir si lo quieres de tipo text o de tipo password.

<input type="text" /> 
<input type="password" />

Pues a esto Vue lo llama props. En otras palabras, los props sirven para pasar parámetros o información al propio web component para poder personalizarlo y ajustarlo dependiendo de las necesidades.

Imagina que quieres crear un componente para mostrar un calendario. En principio puedes crearlo para que siempre se vea y funcione igual, pero también puedes crearlo para que sean más personalizables. Por ejemplo, puedes crearlo con la idea de poder cambiar el número de filas y columnas que se van a mostrar.

De esta forma podrías hacer algo parecido a esto:

<calendar columns="3" rows="6"></calendar>

Vue va más allá y no solo deja pasar números y strings en los props, también deja pasar objetos, arrays y variables reactivas.

Qué son los props y cómo se crean

Los props dentro del componente en el que se declaran no son más que variables. Como pasa con las variables, los props también son reactivos, es decir, cuando desde fuera el valor del prop cambie, automáticamente se actualizará la vista y las propiedades computadas asociadas a ese prop.

Los props se pasan desde el componente padre al componente hijo

Si no sabes lo que es una propiedad computada, te recomiendo que mires antes de continuar este artículo sobre eso:

Variables computadas en Vue

Los props los tienes que declarar dentro de la sección props del componente. A diferencia de las variables que declaras dentro del data, aquí no tienes que hacer un return ni tienes que usar una sintaxis rara, directamente declaras el objeto y dentro cada uno de los props.

<script>
export default {
  props: {
    title: String
  }
};
</script>

Como ves, se declarara el nombre del prop y seguido se pone su tipo.

Los tipos que puedes declarar son:

  • String: Para cadenas de texto.
  • Number: Para números.
  • Boolean: Para booleanos true/false.
  • Array: Listas ya sea de tipos básicos como de objetos.
  • Object: Objetos de javascript.
  • Date: Tipo fecha de javascript.
  • Function: Funciones.
  • Symbol: Símbolos.

Cuando el valor que viene de fuera no coincida con el tipo declarado saltará un error en Vue.

Lo bueno de los props en Vue es que le puedes colocar un valor por defecto en caso de que desde fuera no se pase, para ello el prop lo tienes que crear en forma de Objeto.

<script>
export default {
  props: {
    columns: {
      type: Number,
      default: 4
    },
    rows: {
      type: Number,
      default: 3
    }
  }
};
</script>

En el ejemplo anterior si no pasas filas y no pasas columnas se pondrán su valor declarado a default, 4 y 3 en este ejemplo.

También puedes declarar que el prop tiene que ser obligatorio, es decir, desde fuera al usar el componente siempre tendrías que pasar un valor o de lo contrario salta error. Para declarar la obligatoriedad tienes que usar la sintaxis de objeto también y usar la propiedad required.

<script>
export default {
  props: {
    columns: {
      type: Number,
      required: true
    },
    rows: {
      type: Number,
      default: 3
    }
  }
};
</script>

El prop para las columnas es obligatorio y por tanto no hace falta poner valor por defecto, porque cuando uses este componente siempre vas a tener que declarar ese valor. El prop para las filas en este ejemplo no es obligatorio (si no pones required es como si estuviera a false) y por tanto no hace falta que lo pases siempre.

Por como está hecho Vue, si quieres poner que el valor por defecto de un prop de tipo array sea array vacío, o quieres que un prop de tipo objeto por defecto sea objeto vacío, tienes que hacer este truquito para la propiedad default.

<script>
export default {
  dates: {
    events: {
      type: Array,
      default: () => []
    },
    config: {
      type: Object,
      default: () => {}
    }
  }
};
</script>

Mi consejo es que siempre uses la sintaxis de objeto en los props para que todo esté mucho más claro y que siempre declares la propiedad default.

<script>
export default {
  props: {
    // Evita hacer esto
    text: String,

    // Trata de hacer esto
    size: {
      type: Number,
      default: 0
    }
  }
};
</script>

Cómo usar los props dentro del componente

Los props los tienes que considerar como una variable más del data, es decir, puedes acceder desde cualquier método o computada a los props con el this.

<script>
export default {
  props: {
    columns: {
      type: Number,
      default: 4
    },
    rows: {
      type: Number,
      default: 3
    }
  },
  computed: {
    totalCells() {
      return this.columns * this.rows;
    }
  }
};
</script>

Como es lógico, desde la vista también puedes acceder a los props, igual que con las variables del data:

<template>
  <div class="content">
    <p>Rows: {{rows}}, columns: {{columns}}</p>
  </div>
</template>
<script>
export default {
  props: {
    columns: {
      type: Number,
      default: 4
    },
    rows: {
      type: Number,
      default: 3
    }
  },
  computed: {
    totalMonths() {
      return this.columns * this.rows;
    }
  }
};
</script>

También puedes usar los props dentro de los métodos, incluso dentro de la propiedad created.

<script>
export default {
  props: {
    columns: {
      type: Number,
      default: 4
    },
    rows: {
      type: Number,
      default: 3
    }
  },
  created(){
    console.log("Columns: " + this.columns + " Rows: " + this.rows);
  }
};
</script>

Cómo pasar los props al componente

Para usar un componente con props tienes que importarlo como ya vimos, y en la etiqueta tienes que pasar los props como un atributo más del html, es decir:

<template>
  <div class="home">
    <calendar :rows="6" :columns="5"  />
  </div>
</template>

<script>
// @ es un alias a /src
import Calendar from "@/components/Calendar.vue";

export default {
  components: {
    Calendar
  }
};
</script>

Como pasaba como las propiedades dinámicas que vimos con las vistas, por defecto pasas el valor como string. Para poder pasar números, booleanos, arrays, variables definidas en el data, etc tienes que poner dos puntos antes de la propiedad:

<calendar columns="3" rows="6"></calendar>
<!-- Dentro del componente se reciben los números como string
Por lo tanto dentro del componente no podrías hacer un v-for porque cuenta
como string -->

<calendar :columns="3" :rows="6"></calendar>
<!-- Dentro del componente se reciben los números como números de javascript -->

<calendar :dates="[1,2,4,6,7,9]" :inline="true"></calendar>
<calendar :dates="[1,2,4,6,7,9]" inline></calendar>
<!-- Si quieres pasar un boolean con valor true puedes quitar los puntos
y lo que hay entre comillas para abreviar. Ambas formas son correctas -->

Ejemplo pasando a los props variables definidas en el data:

<template>
  <div class="home">
    <calendar :rows="rows" :columns="columns"  />
  </div>
</template>

<script>
// @ es un alias a /src
import Calendar from "@/components/Calendar.vue";

export default {
  components: {
    Calendar
  },
  data: () => ({
    rows: 6,
    columns: 3
  })
};
</script>

Ejemplo pasando propiedades computadas a los props:

<template>
  <div class="home">
    <calendar :text="text"  />
  </div>
</template>

<script>
// @ es un alias a /src
import Calendar from "@/components/Calendar.vue";

export default {
  components: {
    Calendar
  },
  data: () => ({
    rows: 6,
    columns: 3
  }),
  computed: {
    text() {
      return "Columns: " + this.columns + " Rows: " + this.rows;
    }
  }
};
</script>

Cómo usar los props en el Vue Router

Otra de las cosas que tienes que saber respecto a los props en Vue es que también puedes pasar props al navegar hacia rutas, es decir, los props no solo sirven para para pasar información desde un componente padre a un componente hijo, también puedes pasar props a una ruta cualquiera siempre y cuando estén activados.

Para activar los props en las rutas tienes que poner a true un parámetro especial que tienen las rutas al en el array de rutas que creas al configurar las rutas. Veamos un ejemplo:

router.js

{
  path: "/users",
  name: "users",
  component: Users
  props: true
}

Con eso ya le decimos al vue router que esa ruta puede recibir props desde fuera. Veamos cómo se pasan las rutas al navegar a ellas con vue router.

Si recuerdas en anteriores capítulos vimos como usar Vue router para navegar a rutas. Para pasar props tan solo tienes que pue pasar un objeto params con los props ya puestos con el valor que quieres por ejemplo.

this.$router.push({ name: 'users', params: {title: 'test title' }})

En este caso dentro del componente Users hay definido un prop llamado title.

IMPORTANTE. Solo se pueden pasar props a rutas navegando mediante el nombre del componente name. Si decides navegar a una ruta usando su URL, no se podrán pasar props de esta forma.

Conclusiones

Con los props vas a poder hacer componentes genéricos como botones, encabezados, etc que te van a permitir personalizarlos y usarlos en las condiciones que necesites, por ese motivo son muy usados en las librerías de componentes.

En posteriores capítulos veremos el caso contrario, es decir, pasar información desde el componente hijo al componente padre (por ejemplo saber cuando se pulsa un botón en el componente hijo desde el componente padre).