Desde cero hago casi el blog, que lo tengo abandonado. Una baja laboral (nada grave) y un poco de pereza son los culpables. Pero vamos a darle al código un poco y desempolvamos el teclado.
Ya sabéis que aquí hemos defendido el “no hagas algo que otro haya hecho ya”, siempre podemos adaptar cosas que ya existen, usar plugins, paquetes de React…
“¿Entonces nunca voy a programar desde una hoja (en este caso pantalla) en blanco?”. Hombre, pues alguna vez sí, sobre todo cuando desarrolles funcionalidades muy específicas. En la mayoría de las empresas donde te toque desarrollar, tendran sus plantillas “starter” para proyectos, con lo que todo de cero rara vez te tocará.
Pero hay un caso en el que desarrollar desde cero es lo mejor que puedes hacer: APRENDER. Puedes ser el mayor copy-pasteador del mundo (codo a codo con ChatGPT) pero, haciendo las cosas, las entenderás. Además, tendrás los conceptos mucho más claros para cuando quieras adaptar o arreglar algo.
Venga, al lío, vamos a hacer un carrusel de imágenes. Vamos a usar React y no vamos a instalar ningún paquete que nos valga para lo que queremos, lo vamos a hacer desde cero (en honor al título).
Lo he subido a git, aquí tienes el enlace:
https://github.com/entorno5/carrousel-noplugin-react
Para no entrar mucho en detalles, vamos a destacar lo importante: el truco está en los eventos.
Echa un vistazo al repo, realmente la mandanga está en “src\components\Slider.js”. Vamos a centrarnos primero en el return del componente, donde pintamos el array de images que le llega por props:
return images.length > 0 ? (
<>
<div className="wrapper-content-slider">
<div
className={`image_container ${isCarousel ? "" : "center"}`}
id={`images_${id}`}
onMouseEnter={handleMouseEnter}
>
{mapWithIndex((i, index) => {
return (
<div
key={index}
className="image_content"
id={`ic_${id}_${index + 1}`}
>
<div>
<img
className="image"
alt={i.alt}
src={i.src}
onMouseDown={(e) => e.stopPropagation()}
onTouchStart={(e) => e.stopPropagation()}
draggable="false"
/>
<div className="max_image">
<img src={MaxIcon} alt="max" draggable="false" />
</div>
</div>
</div>
);
}, images)}
</div>
</div>
</>
) : (
""
);
El handleMouseEnter, lanzado en el onMouseEnter de la div que contiene las imágenes pintadas, decide si esa div será o no un carrusel, dependiendo de si cabe en la pantalla o no.
El useEffect que ejecutamos al entrar, se encarga de asignar los listeners que gestionan los eventos de usuario (mousedown y touchstart)
useEffect(() => {
const ele = document.getElementById(`images_${id}`);
if (ele) {
ele.addEventListener("mousedown", mouseDownHandler);
ele.addEventListener("touchstart", touchDownHandler);
}
return () => {
if (ele) {
ele.removeEventListener("mousedown", mouseDownHandler);
ele.removeEventListener("touchstart", touchDownHandler);
}
};
}, []);
Echa un vistazo a los handlers y verás cómo funciona el carrusel. No quiero enrollarme con la explicación: te recuerdo que lo de empezar de cero era para aprender y entender, así que… te toca. Si tienes cualquier duda, ya sabes que ando por aquí.
Solo una cosa más, para defender mi tesis: fíjate en los import que he utilizado en el carrusel:
import React, { useState, useEffect, useRef } from "react";
import { map, addIndex } from "ramda";
import MaxIcon from "../assets/max.svg";
Los propios de React y sus hooks, dos funciones de ramda para ayudar al pintar las imágenes y una imagen (una pista de lo que haremos más adelante). Nada de paquetes, plugins ni similares. O sea, DESDE CERO.
Vamos a añadir funcionalidades en próximas entradas: iremos ampliando las capacidades del carrusel. Con la pista de antes creo que serás capaz de saber por dónde van los tiros. Pero vamos, tampoco es que un carrusel de para más de las cosas que todos conocemos que hace.
Consejo: proponte hacer alguna cosilla desde cero, empieza por algo sencillo, sin pretensiones. El objetivo es que cojas soltura, que es lo importante, sobre todo si te enfrentas a una prueba técnica, donde los cursos y los conocimientos quedan muy bien, pero si no eres resolutivo, no tendrás nada que hacer.
¡Hasta la semana que viene!