I am building a project with Nextjs, React and using Sanity as a CMS.
One of the main components will be a gallery of images that, when you click on of the images you will open an image slider gallery. The images are an array passed in from the CMS.
It's loosely based on the way this website works.. https://www.garrodkirkwood.com/projects/
At the moment, I'm using a simple setState toggle to hide and show the image gallery and the slideshow. The code is far from perfect as there's a lot going on I realise.
WHAT I NEED HELP WITH....
I need to find a way to pass the index of the clicked on image to the event listener so that when you click on the image you open the slideshow on the SAME IMAGE.
I really hope this makes sense.
The user will then exit the slideshow by clicking on 'show thumbnails'
import React, { useState, useEffect, useRef } from "react"; import { css, jsx } from "@emotion/core"; import ImageSliderContent from "./ImageSliderContent"; import styles from "./ImageGrid.module.css"; import ImageGrid from "./ImageGrid"; import ImageSlide from "./ImageSlide"; import Arrow from "./Arrow"; import Dots from "./Dots"; import imageUrlBuilder from "@sanity/image-url"; import client from "../../client"; const builder = imageUrlBuilder(client); const LocationsImageGallery = (props) => { const { caption, image } = props; const images = props.image; const [state, setState] = useState({ translate: 0, transition: 0.45, activeSlide: 0, }); const [showSlider, setShowSlider] = useState(false); const { translate, transition, activeSlide, _slides } = state; const size = useWindowSize(); const transitionRef = useRef(); function useWindowSize() { const isClient = typeof window === "object"; function getSize() { return { width: isClient ? window.innerWidth : undefined, }; } const [windowSize, setWindowSize] = useState(getSize); useEffect(() => { if (!isClient) { return false; } function handleResize() { setWindowSize(getSize()); } window.addEventListener("resize", handleResize); return () => window.removeEventListener("resize", handleResize); }, []); return windowSize; } const nextSlide = () => { if (activeSlide === images.length - 1) { return setState({ ...state, translate: 0, activeSlide: 0, }); } setState({ ...state, activeSlide: activeSlide + 1, translate: (activeSlide + 1) * size.width, }); }; const prevSlide = () => { if (activeSlide === 0) { return setState({ ...state, translate: (images.length - 1) * size.width, activeSlide: images.length - 1, }); } setState({ ...state, activeSlide: activeSlide - 1, translate: (activeSlide - 1) * size.width, }); }; const show = () => { setShowSlider(true); }; const hide = () => { setShowSlider(false); }; return ( <div className={styles.root}> <div className={styles.imageGridContainer}> {images.map((image, index) => ( <div className={styles.imageContainer} onClick={show}> <img src={builder.image(image).auto("format").width(2000).url()} className={styles.image} alt={image.caption} key={index} /> <p className={styles.caption}>{image.caption}</p> </div> ))} </div> {showSlider && ( <div className={styles.imageGalleryContainer}> <div css={ImageSliderCSS}> <ImageSliderContent translate={translate} transition={transition} width={size.width * images.length} > {images.map((image, index) => ( <ImageSlide key={image + index} content={builder.image(image).auto("format").width(2000).url()} ></ImageSlide> ))} </ImageSliderContent> <Arrow direction="left" handleClick={prevSlide} /> <Arrow direction="right" handleClick={nextSlide} /> <Dots slides={images} activeSlide={activeSlide} /> </div> <a href="" onClick={hide}> Show Thumbnails </a> </div> )} </div> ); }; const ImageSliderCSS = css` position: relative; height: 500px; width: 750px; margin: 0 auto; overflow: hidden; `; export default LocationsImageGallery;
UPDATED WITH PASSING INDEX TO CLICK EVENT
import React, { useState, useEffect, useRef } from "react";
import { css, jsx } from "@emotion/core";
import ImageSliderContent from "./ImageSliderContent";
import styles from "./LocationsImageGallery.module.css";
import ImageGrid from "./ImageGrid";
import ImageSlide from "./ImageSlide";
import Arrow from "./Arrow";
import Dots from "./Dots";
import imageUrlBuilder from "@sanity/image-url";
import client from "../../client";
const builder = imageUrlBuilder(client);
const LocationsImageGallery = (props) => {
const { caption, image } = props;
const images = props.image;
const [state, setState] = useState({
translate: 0,
transition: 0.45,
activeSlide: 0,
});
const [showSlider, setShowSlider] = useState(false);
const [showGrid, setShowGrid] = useState(true);
const { translate, transition, activeSlide, _slides } = state;
const size = useWindowSize();
const transitionRef = useRef();
function useWindowSize() {
const isClient = typeof window === "object";
function getSize() {
return {
width: isClient ? window.innerWidth : undefined,
};
}
const [windowSize, setWindowSize] = useState(getSize);
useEffect(() => {
if (!isClient) {
return false;
}
function handleResize() {
setWindowSize(getSize());
}
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
return windowSize;
}
const nextSlide = () => {
if (activeSlide === images.length - 1) {
return setState({
...state,
translate: 0,
activeSlide: 0,
});
}
setState({
...state,
activeSlide: activeSlide + 1,
translate: (activeSlide + 1) * size.width,
});
};
const prevSlide = () => {
if (activeSlide === 0) {
return setState({
...state,
translate: (images.length - 1) * size.width,
activeSlide: images.length - 1,
});
}
setState({
...state,
activeSlide: activeSlide - 1,
translate: (activeSlide - 1) * size.width,
});
};
const show = (index) => {
setShowGrid(false);
setShowSlider(true);
setState({ activeSlide: index });
};
const hide = () => {
setShowSlider(false);
setShowGrid(true);
};
return (
<div className={styles.root}>
<div className={styles.header}>
<a href="/locations">X</a>
</div>
{showGrid && (
<div className={styles.imageGrid}>
<div className={styles.imageGridContainer}>
{images.map((image, index, caption) => (
<div className={styles.imageContainer} onClick={() => show(index)}>
<img
src={builder.image(image).auto("format").width(2000).url()}
className={styles.image}
alt={image.caption}
key={index}
/>
<p className={styles.caption}>{image.caption}</p>
</div>
))}
</div>
</div>
)}
{showSlider && (
<div className={styles.imageGalleryContainer}>
<div className={styles.imageSlider}>
<ImageSliderContent
translate={translate}
transition={transition}
width={size.width * images.length}
>
{images.map((image, index, caption) => (
<>
<ImageSlide
key={image + index}
content={builder.image(image).auto("format").url()}
></ImageSlide>
</>
))}
</ImageSliderContent>
<Arrow direction="left" handleClick={prevSlide} />
<Arrow direction="right" handleClick={nextSlide} />
</div>
<div className={styles.infoBar}>
<p className={styles.infoCaption}>
Locations / <span>{image.caption}</span>
</p>
<a href="" onClick={hide} className={styles.infoThumbnails}>
Show Thumbnails
</a>
</div>
</div>
)}
</div>
);
};
export default LocationsImageGallery;
This version, doesn't seem to be updating the state, console.log of activeSlide and state...
LocationsImageGallery.js?0692:94 {activeSlide: 8, state: {…}} activeSlide: 8 state: activeSlide: 0 transition: 0.45 translate: 0 proto: Object proto: Object