Skip to content

Unidad 8: Renderizado de Listas en Vue.js

Objetivo: Aprender a renderizar listas de elementos dinámicamente en Vue.js, utilizando la directiva v-for, la propiedad key y cómo mejorar la estructura del código.

En este punto, tenemos un componente completamente funcional; estamos listos para agregar varios componentes ToDoItem a nuestra aplicación. Veremos cómo agregar un conjunto de datos de elementos de tareas a nuestro componente App.vue, que luego recorreremos y mostraremos dentro de los componentes ToDoItem mediante la directiva v-for.


8.1 Introducción al Renderizado de Listas en Vue.js

¿Por qué necesitamos renderizar listas en Vue.js?

En muchas aplicaciones web es común manejar colecciones de datos, como listas de productos, tareas o entradas de blog. En lugar de escribir cada elemento manualmente en el HTML, Vue nos permite generar listas dinámicamente a partir de datos.

Ejemplo de una lista estática vs dinámica

Lista Estática

1
2
3
4
5
<ul>
  <li>Aprender Vue.js</li>
  <li>Practicar con un proyecto</li>
  <li>Construir una aplicación</li>
</ul>

Este enfoque funciona para listas pequeñas, pero en aplicaciones reales los datos pueden provenir de una API o de una base de datos. Con lo cual la visión estática no es escalable.

Con Vue.js podemos usar v-for para recorrer un array y generar los elementos dinámicamente.


8.2 La Directiva v-for

Uso de v-for para iterar sobre arrays

La directiva v-for se utiliza para recorrer arrays y objetos en Vue.js. Permite renderizar elementos de manera dinámica. Su uso es parecido al bucle for ... of ... de JavaScript.

Ejemplo de v-for

<template>
<ul>
    <li v-for="tarea in tareas" :key="tarea.id" :done="tarea.done">{{ tarea.texto }}</li>
</ul>
</template>

<script>
export default {
data() {
    return {
    tareas: [
        { id: 1, texto: 'Aprender Vue.js', done: false },
        { id; 2, texto: 'Practicar con un proyecto', done: false },
        { id: 3, texto: 'Construir una aplicación', done: false }
    ]
    };
}
};
</script>

Explicación:

  • v-for="tarea in tareas" → Itera sobre el array tareas.
  • {{ tarea.texto }} → Muestra el contenido dinámicamente.
  • :key="tarea.id" → Identificador único para optimizar la actualización del DOM.

8.3 Uso de la Propiedad key en Listas

Vue usa la propiedad key para identificar cada elemento de la lista de manera eficiente.

Buenas prácticas con key

Siempre usar un identificador único como un id de la base de datos o un índice.
No usar índices como key si los elementos pueden cambiar de orden.
Si no hay un id, generar uno único.

Ejemplo de key con ID

1
2
3
<li v-for="usuario in usuarios" :key="usuario.id">
  {{ usuario.nombre }}
</li>

8.4 Integración de v-for en ToDoList

En aplicaciones más grandes, en lugar de listar directamente en el template, es mejor usar componentes reutilizables. Vamos a continuar con el ejemplo de la lista de tareas, modificando el componente ToDoList para que utilice un componente ToDoItem.

📌 Ejemplo de ToDoItem.vue

Comenzamos po añadir algundos datos para renderizar en el componente ToDoItem. Este componente recibe una prop llamada texto y la muestra en un <li>. Necesitamos añadir un array de tareas en el componente ToDoList y recorrerlo con v-for.

Código de ToDoItem.vue con v-for

<script>
  import ToDoItem from './ToDoItem.vue';
  export default {
    name: 'ToDoList',
    components: {
      ToDoItem,
    },
    data() {
      return {
        tareas: [
        { label: "Learn Vue", done: false },
        { label: "Create a Vue project with the CLI", done: true },
        { label: "Have fun", done: true },
        { label: "Create a to-do list", done: false },
        ],
      };
    },
  };
</script>

Ahora tenemos una lista de tareas en el componente ToDoList. Vamos a modificar el template para recorrer el array de tareas y renderizar un componente ToDoItem por cada tarea. utilizaremos v-for para recorrer el array.

Atributo clave

Antes de hacer eso, hay otra pieza de sintaxis que hay que saber que se usa con v-for, el atributo key. Para ayudar a Vue a optimizar la representación de los elementos de la lista, intenta parchear los elementos de la lista para que no los recree cada vez que la lista cambia. Sin embargo, Vue necesita ayuda. Para asegurarse de que está reutilizando los elementos de la lista adecuadamente, necesita una "clave" única en el mismo elemento al que se adjunta v-for.

Para asegurarse de que Vue pueda comparar con precisión los atributos key, deben ser valores de cadena o numéricos. Si bien sería genial usar el campo de nombre, este campo eventualmente será controlado por la entrada del usuario, lo que significa que no podemos garantizar que los nombres sean únicos. Sin embargo, podemos usar name.id como clave, ya que es único.

Importar nanoid en el componente ToDoItem.vue.

Código de ToDoItem.vue con nanoid

1
2
3
  <script>
  import { nanoid } from 'nanoid';
  </script>

Añadir un id único a cada tarea en el array. Para ello utilizaremos: "todo-" + nanoid().

Código de ToDoItem.vue con nanoid

import ToDoItem from "./components/ToDoItem.vue";
import { nanoid } from "nanoid";

export default {
  name: "app",
  components: {
    ToDoItem,
  },
  data() {
    return {
      ToDoItems: [
        { id: "todo-" + nanoid(), label: "Learn Vue", done: false },
        {
          id: "todo-" + nanoid(),
          label: "Create a Vue project with the CLI",
          done: true,
        },
        { id: "todo-" + nanoid(), label: "Have fun", done: true },
        {
          id: "todo-" + nanoid(),
          label: "Create a to-do list",
          done: false,
        },
      ],
    };
  },
};

Ahora ya podemos añadir la directiva v-for en el componente ToDoList para recorrer el array de tareas y renderizar un componente ToDoItem por cada tarea.

Código de ToDoList.vue con v-for

  <template>
    <div>
      <ul>
        <ToDoItem
          v-for="item in ToDoItems"
          :key="item.id"
          :label="item.label"
          :done="item.done"
        />
      </ul>
    </div>
  </template>

Al realizar este cambio, todas las expresiones JavaScript entre las etiquetas <li> tendrán acceso al valor del elemento, además de a los demás atributos del componente. Esto significa que podemos pasar los campos de nuestros objetos de elemento a nuestro componente ToDoItem; solo recuerda usar la sintaxis v-bind. Esto es muy útil, ya que queremos que nuestros elementos de tarea muestren sus propiedades de etiqueta como su etiqueta, no como una etiqueta estática de "Mi elemento de tarea". Además, queremos que su estado de marcado refleje sus propiedades de completado, no siempre como done="true".

Vamos a realizar una pequeña refactorización

Hay una pequeña refactorización que podemos hacer aquí. En lugar de generar el id para las casillas de verificación dentro del componente ToDoItem, podemos convertir el id en una propiedad. Si bien esto no es estrictamente necesario, nos facilita la gestión, ya que de todos modos necesitamos crear un id único para cada elemento de la lista de tareas.

  1. Agrega una nueva propiedad a tu componente ToDoItem: id.
  2. Hazlo obligatorio y haz que sea un tipo String.
  3. Para evitar conflictos de nombres, elimina el campo id de tu atributo data.
  4. Ya no usas nanoid, por lo que debes eliminar la línea import { nanoid } from 'nanoid'; de lo contrario, tu aplicación generará un error.

El contenido de <script> en tu componente ToDoItem debería verse ahora así:

Código de ToDoItem.vue con id

<script>
export default {
  props: {
    label: { required: true, type: String },
    done: { default: false, type: Boolean },
    id: { required: true, type: String },
  },
  data() {
    return {
      isDone: this.done,
    };
  },
};
</script>

8.5 Tarea Práctica: Implementación en el Proyecto del Blog

Objetivo: Usar v-for para mostrar múltiples entradas, asegurando un key único y reflejando visualmente si un post es destacado.

Pasos a seguir:

1️⃣ Modificar BlogList.vue para iterar sobre una lista de entradas con v-for.
2️⃣ Usar BlogPost.vue para renderizar cada entrada, asegurando :key="post.id".
3️⃣ Añadir una prop destacado para mostrar si un post es importante (pero sin modificarlo desde la UI).


🔒 Nueva Solución del Blog (oculta inicialmente)

Código de BlogPost.vue

Código de BlogPost.vue
<template>
  <div class="card mb-3" :class="{ 'bg-warning': destacado }">
    <div class="card-body">
      <h5 class="card-title">{{ titulo }}</h5>
      <p class="card-text">{{ contenido }}</p>
      <p v-if="destacado"><strong>Post Destacado</strong></p>
    </div>
  </div>
</template>

<script>
export default {
  name: 'BlogPost',
  props: {
    titulo: String,
    contenido: String,
    destacado: Boolean
  }
};
</script>

Código actualizado de BlogList.vue

Código de BlogList.vue
<template>
  <div class="container mt-4">
    <h2 class="text-center">Lista de Entradas</h2>
    <BlogPost 
      v-for="post in posts" 
      :key="post.id" 
      :titulo="post.titulo" 
      :contenido="post.contenido"
      :destacado="post.destacado"
    />
  </div>
</template>

<script>
import BlogPost from './BlogPost.vue';

export default {
  components: { BlogPost },
  data() {
    return {
      posts: [
        { id: 1, titulo: 'Primer post', contenido: 'Este es mi primer post en Vue.js.', destacado: false },
        { id: 2, titulo: 'Aprendiendo Vue', contenido: 'Hoy aprendí sobre `v-for`.', destacado: true }
      ]
    };
  }
};
</script>
Explicación de la solución

Explicación de la solución:

  • Cada entrada tiene un id único.
  • El checkbox no es necesario, ya que aún no hemos visto eventos.
  • Los posts destacados se resaltan visualmente con bg-warning (fondo amarillo en Bootstrap).
  • Se usa v-if="destacado" para mostrar un mensaje si el post es importante.

Este ejercicio permitirá a los alumnos aplicar v-for y key en su proyecto del Blog, generando listas dinámicas de manera eficiente.