Estoy tratando de crear una función que represente los 4 resultados siguientes y anteriores en una matriz de objetos al hacer clic. Actualmente solo estoy devolviendo los primeros 4 elementos y sus imágenes y ajustando los valores en la declaración de devolución onClick y no estoy satisfecho con esta solución. ¿Algún consejo?
const ImageSlider = ({ loadData, data, setData }) => { const [current, setCurrent] = useState(0); const length = data.length; const [test, setTest] = useState(0); const [another, setAnother] = useState(4); useEffect(() => { loadData().then((data) => setData(data)); }, []); const getNextSlide = () => { setCurrent(current === length - 1 ? 0 : current + 1); if (current / 3 === 1) { setTest(test + 4); setAnother(another + 4); } }; const getPrevSlide = () => { setCurrent(current === 0 ? length - 1 : current - 1); // setTest(test - 1); // setAnother(another - 1); }; console.log(current); if (!Array.isArray(data) || length <= 0) { return null; // Need that error message here } return ( <div className="slider"> <FaArrowCircleLeft className="slider-left-arrow" onClick={getPrevSlide} /> <FaArrowCircleRight className="slider-right-arrow" onClick={getNextSlide} /> {data.slice(test, another).map((program, index) => { return ( <div className={ index === current ? "slider-active-program" : "slider-inactive-program" } key={index} > <img src={program.image} alt="program" className="slider-program-image" /> </div> ); })} </div> ); }; export default ImageSlider;Este puede ser un enfoque posible para lograr el objetivo deseado:
const ImageSlider = ({ loadData, data, setData }) => { const imageLength = 4; // number of images to be shown per-page const totalImages = data.length; const [startAt, setStartAt] = useSate(0); // start rendering from image-0 useEffect(() => { loadData().then((data) => setData(data)); }, []); const switchImages = (direction = 'forward') => ( setStartAt(prev => { if (direction === 'forward') { // if there are more images, reposition 'startAt' to next set if (prev + imageLength < totalImages) return prev + imageLength; return 0; // reset back to image-0 } else { // if there is previous set, reposition to it's start if (prev - imageLength >= 0) return prev - imageLength; // otherwise, reposition to the start of the last-set return (Math.floor((totalImages - 1) / imageLength) * imageLength) }; }) ); return ( <div className="slider"> <FaArrowCircleLeft className="slider-left-arrow" onClick={() => switchImages('reverse')} /> <FaArrowCircleRight className="slider-right-arrow" onClick={() => switchImages()} /> {Array.isArray(data) && data.filter((el, idx) => idx >= startAt && idx < (startAt + imageLength)).map((program, index) => { return ( <div className={ index === current ? "slider-active-program" : "slider-inactive-program" } key={index} > <img src={program.image} alt="program" className="slider-program-image" /> </div> ); })} </div> ); }; export default ImageSlider;Explicación
imageLength es fijo (establecido en 4 )startAt es una variable de estado (inicialmente establecida en 0)data se procesan al return solo cuando se trata de una ArrayswitchImages es un método invocado en los eventos de clic de flecha left-arrow y right-arrow (cambiando la direction del parámetro para reverse en left-arrow )startAt se actualiza en función de la direction , el valor prev , las totalImages y la imageLength de la imagen.Sugerencia
Si uno necesita enviar un mensaje al usuario de que la matriz de data aún no se ha cargado o está empty , se puede lograr cambiando {Array.isArray(data) && .... en un condicional como {Array.isArray(data) ? ....<existing> : <some message here> .
Advertencia
El código anterior es solo un enfoque. No está probado y puede contener errores de sintaxis u otros problemas. Utilice los comentarios para compartir comentarios y esta respuesta puede actualizarse en consecuencia.
No creo que tengas que cambiar mucho tu enfoque para obtener lo que estás buscando aquí.
Para representar las imágenes a la izquierda y a la derecha de su selección actual y permitir el bucle desde el frente hacia atrás (como parece que quiere hacer), podemos pegar una copia de la matriz al frente y atrás y seleccionar el medio rodaja. Es un poco como esto:
La implementación solo requeriría que reemplace el método .map(...) actual en su declaración de devolución con este:
[...data, ...data, ...data].slice( length + current - peekLeft, length + current + peekRight + 1 ).map((program, index) => { ... } Y luego también puede eliminar la test y another objetos de estado, ya que no son necesarios. Solo necesita agregar peekLeft y peekRight o reemplazarlos en línea dentro de la instrucción .map(...) . La primera opción puede ser algo como esto:
const peekLeft = 4; const peekRight = 4; const ImageSlider = ({ loadData, data, setData }) => { ... }