Home > OS >  Building lightbox in React. Clicking first image shows, then the next images are empty objects
Building lightbox in React. Clicking first image shows, then the next images are empty objects

Time:01-09

building this lightbox in React, the problem I am facing is that when I goto the next image in the array, it's empty and just showing "Object object" as the error. I am grabbing both the image and text from the array of objects. Anyone have any ideas? The showNext() function is where it's not working. Thanks

import { useState } from 'react';
import Ant from '../../img/ant.jpeg';
import Bee from '../../img/bee.jpeg';
import Bedbug from '../../img/bedbug.jpeg';
import Wasp from '../../img/wasp.jpeg';
import Mouse from '../../img/mouse.jpeg'

// const images = [Bee, Ant, Bedbug, Wasp, Mouse];

const images_arr = [
  { image: Ant, text: "Ant" },
  { image: Bee, text: "Bee" },
  { image: Bedbug, text: "Bedbug" },
  { image: Mouse, text: "Mice" },
  { image: Wasp, text: "Wasp" },
]

function PestsGallery() {
  const [imageToShow, setImageToShow] = useState({});
  const [lightboxDisplay, setLightBoxDisplay] = useState(false);

  //looping through our images array to create img elements
  const imageCards = images_arr.map(({ image, text }) => (
    <>
      <span>{text}</span>
      <img key={image} alt={image} className="image-card" onClick={() => showImage(image)} src={image} />
    </>

  ));

  //function to show a specific image in the lightbox, amd make lightbox visible
  const showImage = (image) => {
    setImageToShow(image);
    setLightBoxDisplay(true)
  }

  //hide lightbox
  const hideLightBox = () => {
    setLightBoxDisplay(false)
  }

  //show next image in lightbox - this is where the error is happening, when i clicke the arrow the next image is empty.
  const showNext = (e) => {
    e.stopPropagation();
    let currentIndex = images_arr.indexOf(imageToShow);
    if (currentIndex >= images_arr.length - 1) {
      setLightBoxDisplay(false)
    } else {
      let nextImage = images_arr[currentIndex   1];
      setImageToShow(nextImage)
    }
  }

  const showPrev = (e) => {
    e.stopPropagation();
    let currentIndex = images_arr.indexOf(imageToShow);
    if (currentIndex <= 0) {
      setLightBoxDisplay(false);
    } else {
      let nextImage = images_arr[currentIndex - 1];
      setImageToShow(nextImage);
    }
  };


  return (
    <>
      <h2> Bugs we treat</h2>
      <div>{imageCards}</div>
      {
        lightboxDisplay ?
          <div id="lightbox" onClick={hideLightBox}>
            <button onClick={showPrev}>⭠</button>
            <img alt="gallery" id="lightbox-img" src={imageToShow}></img>
            <button onClick={showNext}>⭢</button>
          </div>
          : ""
      }
    </>
  );
}

export default PestsGallery;

CodePudding user response:

Inconsistent types of imageToShow local state seems to be at fault (cannot test this without the actual repo). Typescript is great at catching this early.

imageToShow state has this type: { image: .jpeg, text: string }.

In imageCards callback on the img you pass { image: .jpeg } into showImage function, which then uses setImageToShow to set the image to show. Instead, you should be passing the correct state shape i.e. { image, text }.

Also, in your jsx, you need to access the image component in img tag like so: <img alt="gallery" id="lightbox-img" src={imageToShow.image}></img>

If you look at your setImageToShow calls in showNext and showPrev, the nextImage variable is the entire image object e.g. { image: Bee, text: "Bee" }, since you access images_arr at a specific index (btw, keep you naming consistent to camelCase).

Code snippet aligned with above below for copy paste check:

import { useState } from 'react'
import Ant from '../../img/ant.jpeg'
import Bee from '../../img/bee.jpeg'
import Bedbug from '../../img/bedbug.jpeg'
import Wasp from '../../img/wasp.jpeg'
import Mouse from '../../img/mouse.jpeg'

// const images = [Bee, Ant, Bedbug, Wasp, Mouse];

const images_arr = [
  { image: Ant, text: 'Ant' },
  { image: Bee, text: 'Bee' },
  { image: Bedbug, text: 'Bedbug' },
  { image: Mouse, text: 'Mice' },
  { image: Wasp, text: 'Wasp' },
]

function PestsGallery() {
  const [imageToShow, setImageToShow] = useState({})
  const [lightboxDisplay, setLightBoxDisplay] = useState(false)

  //looping through our images array to create img elements
  const imageCards = images_arr.map(({ image, text }) => (
    <>
      <span>{text}</span>
      <img
        key={image}
        alt={image}
        className='image-card'
        onClick={() => showImage({ image, text })}
        src={image}
      />
    </>
  ))

  //function to show a specific image in the lightbox, amd make lightbox visible
  const showImage = (image) => {
    setImageToShow(image) // image is the object hence it will work
    setLightBoxDisplay(true)
  }

  //hide lightbox
  const hideLightBox = () => {
    setLightBoxDisplay(false)
  }

  //show next image in lightbox - this is where the error is happening, when i clicke the arrow the next image is empty.
  const showNext = (e) => {
    e.stopPropagation()
    let currentIndex = images_arr.indexOf(imageToShow)
    if (currentIndex >= images_arr.length - 1) {
      setLightBoxDisplay(false)
    } else {
      let nextImage = images_arr[currentIndex   1]
      setImageToShow(nextImage)
    }
  }

  const showPrev = (e) => {
    e.stopPropagation()
    let currentIndex = images_arr.indexOf(imageToShow)
    if (currentIndex <= 0) {
      setLightBoxDisplay(false)
    } else {
      let nextImage = images_arr[currentIndex - 1]
      setImageToShow(nextImage)
    }
  }

  return (
    <>
      <h2> Bugs we treat</h2>
      <div>{imageCards}</div>
      {lightboxDisplay ? (
        <div id='lightbox' onClick={hideLightBox}>
          <button onClick={showPrev}>⭠</button>
          <img alt='gallery' id='lightbox-img' src={imageToShow.image}></img>
          <button onClick={showNext}>⭢</button>
        </div>
      ) : (
        ''
      )}
    </>
  )
}

export default PestsGallery
  •  Tags:  
  • Related