Search code examples
javascriptreactjsreact-multi-carousel

How to make my react-multi-carousel use a light-box feature for my ReactJS app


I have images coming in from a rest api, into my application. Those images then get populated into a react-multi-carousel. What I would like to do is to make those images clickable for a light-box. I am fairly new to React. My code for the carousel slider so far is:

slider.js

  import React, { Component } from 'react';
  import '../slider/slider.css';
  import Carousel from "react-multi-carousel";
  import "react-multi-carousel/lib/styles.css";

  const responsive = {
      superLargeDesktop: {
          breakpoint: { max: 4000, min: 3000 },
          items: 1,
      },
      desktop: {
          breakpoint: { max: 3000, min: 1024 },
          items: 1,
      },
      tablet: {
          breakpoint: { max: 1024, min: 464 },
          items: 1,
      },
      mobile: {
          breakpoint: { max: 464, min: 0 },
          items: 1,
      },
  };

  class Slider extends Component {
      _isMounted = false;

      state = {
          awsApiData: [],
          loading: false,
      }

      componentDidMount() {
          this._isMounted = true;
          console.log('app mounted');
          this.setState({ loading: true });
          /*global fetch */
          fetch('https://onelbip0e6.execute-api.eu-west-2.amazonaws.com/xxxxx')
              .then(data => data.json())
              .then(data => this.setState({ awsApiData: data[0], loading: false }, () => console.log(data)));
      }
      componentWillUnmount() {
          this._isMounted = false;
      }

      render() {
          return (
              <div>
              {this.state.loading
                    ? <div className="text-center">Loading...</div>
                    : 
                        <Carousel
                            additionalTransfrom={0}
                            showDots={false}
                            arrows={true}
                            autoPlaySpeed={3000}
                            autoPlay={false}
                            centerMode={false}
                            className="slider"
                            containerClass="container-with-dots"
                            dotListClass="dots"
                            draggable
                            focusOnSelect={false}
                            infinite
                            itemClass="carousel-top"
                            keyBoardControl
                            minimumTouchDrag={80}
                            renderButtonGroupOutside={false}
                            renderDotsOutside
                            responsive={responsive}>
                           {Object.values(this.state.awsApiData).map((post, indx) => {
  return (
      <div className="mt-5" key={indx}>
          <img className="media-img card-img-top card-img-hero" src={post.image} alt="Alt text"></img>

      </div>
  );
})}
                        </Carousel>
              }
                        </div>
          );
      }
  }

  export default Slider;

Solution

  • You can do the lightbox by hand by issuing an onClick for each image and enlarging the image, adding captions, full screen etc.

    It is a lot easier if you can make use of existing libraries to implement lightbox feature for your carousal such as react-images.

    Here is the working copy of your code with light box feature implemented(using react-multi-carousel and react-images).

    https://codesandbox.io/s/react-multi-corousal-issue-72s9o?file=/src/Slider.js

    Here is the code snippet.

    import React, { Component } from "react";
    // import "../slider/slider.css";
    import "./slider.css";
    import Carousel from "react-multi-carousel";
    import "react-multi-carousel/lib/styles.css";
    import LightBox, { Modal, ModalGateway } from "react-images";
    
    const responsive = {
      superLargeDesktop: {
        breakpoint: { max: 4000, min: 3000 },
        items: 1
      },
      desktop: {
        breakpoint: { max: 3000, min: 1024 },
        items: 1
      },
      tablet: {
        breakpoint: { max: 1024, min: 464 },
        items: 1
      },
      mobile: {
        breakpoint: { max: 464, min: 0 },
        items: 1
      }
    };
    
    class Slider extends Component {
      _isMounted = false;
    
      state = {
        awsApiData: [],
        loading: false,
        selectedIndex: 0,
        lightboxIsOpen: false
      };
    
      componentDidMount() {
        this._isMounted = true;
        console.log("app mounted");
        this.setState({ loading: true });
        /*global fetch */
        // fetch("https://onelbip0e6.execute-api.eu-west-2.amazonaws.com/xxxxx")
        fetch("https://picsum.photos/v2/list?page=1&limit=10")
          .then(data => data.json())
          .then(data =>
            // this.setState({ awsApiData: data[0], loading: false }, () =>
            this.setState(
              {
                awsApiData: data.map(item => ({ source: item.download_url })),
                loading: false
              },
              () => console.log(data)
            )
          );
      }
      componentWillUnmount() {
        this._isMounted = false;
      }
    
      toggleLightbox = selectedIndex => {
        this.setState(state => ({
          lightboxIsOpen: !state.lightboxIsOpen,
          selectedIndex
        }));
      };
    
      render() {
        return (
          <div>
            {this.state.loading ? (
              <div className="text-center">Loading...</div>
            ) : (
              <>
                <Carousel
                  additionalTransfrom={0}
                  showDots={false}
                  arrows={true}
                  autoPlaySpeed={3000}
                  autoPlay={true}
                  centerMode={false}
                  className="slider"
                  containerClass="container-with-dots"
                  dotListClass="dots"
                  draggable
                  focusOnSelect={false}
                  infinite
                  itemClass="carousel-top"
                  keyBoardControl
                  minimumTouchDrag={80}
                  renderButtonGroupOutside={false}
                  renderDotsOutside
                  responsive={responsive}
                >
                  {Object.values(this.state.awsApiData).map((post, indx) => {
                    return (
                      <div
                        className="mt-5"
                        key={indx}
                        onClick={() => this.toggleLightbox(indx)}
                      >
                        <img
                          className="media-img card-img-top card-img-hero"
                          src={post.source}
                          alt="Alt text"
                        />
                      </div>
                    );
                  })}
                </Carousel>
                <ModalGateway>
                  {this.state.lightboxIsOpen ? (
                    <Modal onClose={this.toggleLightbox}>
                      <LightBox
                        components={{
                          FooterCaption: () => <div>footer caption</div>
                        }}
                        currentIndex={this.state.selectedIndex}
                        // formatters={{ getAltText }}
                        frameProps={{ autoSize: "height" }}
                        views={this.state.awsApiData}
                      />
                    </Modal>
                  ) : null}
                </ModalGateway>
              </>
            )}
          </div>
        );
      }
    }
    
    export default Slider;