El bug de Swiper Loop que casi me vuelve loca

Crónica de una batalla contra un carrusel infinito y cómo un simple warning escondía un problema más profundo.

DebugReactSwiper.js

El Problema (Para el Recruiter)

En mi portafolio, quería un carrusel de proyectos atractivo y dinámico. La librería Swiper.js es fantástica para esto. Decidí implementar la función loop: true para que el carrusel fuera infinito. Parecía sencillo, pero me topé con un muro: el carrusel se rompía o, peor aún, aparecía un warning en la consola: Swiper Loop Warning: The number of slides is not enough for loop mode...

Un visitante normal (como un recruiter) no ve la consola, pero sí ve un carrusel que no funciona bien. Eso proyecta una imagen de falta de atención al detalle. Mi primer instinto fue "desactivar el loop y listo", pero eso era rendirse.

El Dilema: ¿Ignorar un warning y entregar una funcionalidad a medias, o pararse a entender qué está pasando realmente?

La Solución (Para el Desarrollador)

Tras investigar, descubrí cómo funciona el loop de Swiper por dentro. Para crear un bucle "infinito", Swiper necesita duplicar tus slides (diapositivas). Si le dices que muestre 3 slides a la vez (slidesPerView: 3), necesita al menos el doble (6 slides en total) para que el efecto funcione sin saltos.

Mi portafolio tiene 5 proyectos. No eran suficientes.

El problema real era una "condición de carrera" (race condition). Mi componente de React cargaba los 5 proyectos, pero Swiper se inicializaba antes de que los proyectos estuvieran listos, veía "0 slides" y fallaba.

La solución fue tomar el control del estado. En lugar de dejar que Swiper se inicializara solo, usé el hook useState para guardar la instancia de Swiper y el hook useEffect para detectar cuándo mis datos (los proyectos) estaban cargados. Solo entonces, actualizaba Swiper manualmente.

// Ejemplo simplificado:
const [swiperInstance, setSwiperInstance] = useState(null);
const [projects, setProjects] = useState([]);

// 1. Capturamos la instancia de Swiper
<Swiper onSwiper={setSwiperInstance}>
  ...
</Swiper>

// 2. Cargamos los datos (ej: en otro useEffect)
useEffect(() => {
  setProjects(projectsData);
}, []);

// 3. Cuando los datos cambian, actualizamos Swiper
useEffect(() => {
  if (swiperInstance && projects.length > 0) {
    swiperInstance.update();
  }
}, [swiperInstance, projects]);

Al final, decidí que el loop: false era más limpio para un portafolio con 5 proyectos, pero ahora entendía por qué fallaba, y eso es lo importante.

La Lección Aprendida

No ignores los warnings. Un warning no es un error que rompa la app, pero casi siempre es un síntoma de un problema más profundo. Entender por qué aparece un warning es lo que diferencia a un desarrollador junior de uno senior.