Following on from: How to make my react-multi-carousel use a light-box feature for my ReactJS app
My app is using react-images for lightbox and react-carousel-images for the carousel. My api has a title and image. Problem I have is the title in the footer caption is always coming as the image selected and not changing when in the lightbox carousel. I think it is to do with the index of the selected image? My code so far is:
example of issue: https://codesandbox.io/s/react-multi-corousal-issue-72s9o?file=/src/Slider.js
slider.js
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,
selectedImage: {},
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/livestage/imgApi")
.then(data => data.json())
.then(data =>
// this.setState({ awsApiData: data[0], loading: false }, () =>
this.setState(
{
// awsApiData: data.map(item => ({source: item.download_url })),
awsApiData: data.map(item => ({
...item,
source: item.image
})),
loading: false
},
() => console.log(data)
)
);
}
componentWillUnmount() {
this._isMounted = false;
}
toggleLightbox = (post, selectedIndex) => {
// this.setState(state => ({
// lightboxIsOpen: !state.lightboxIsOpen,
// selectedIndex
// }));
this.setState(state => ({
lightboxIsOpen: !state.lightboxIsOpen,
selectedImage: { title: post.title, index: selectedIndex }
}));
};
render() {
return (
<div>
{this.state.loading ? (
<div className="text-center">Loading...</div>
) : (
<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)}
onClick={() => this.toggleLightbox(post, indx)}
>
<img
className="media-img card-img-top card-img-hero"
src={post.source}
alt="Alt text"
style={{ cursor: "pointer" }}
/>
</div>
);
})}
</Carousel>
<ModalGateway>
{this.state.lightboxIsOpen ? (
<Modal onClose={this.toggleLightbox}>
<LightBox
components={{
FooterCaption: () => <div>{this.state.selectedImage.title}</div>
}}
//currentIndex={this.state.selectedIndex}
currentIndex={this.state.selectedImage.index}
// formatters={{ getAltText }}
frameProps={{ autoSize: "height" }}
views={this.state.awsApiData}
/>
</Modal>
) : null}
</ModalGateway>
</div>
)}
</div>
);
}
}
export default Slider;
Your caption is set to this.state.selectedImage.title but you never update the state (i.e. call setState()) when your light box view changes.
You need to add the onViewChange handler to the LightBox component:
<LightBox onViewChange={handleLightBoxViewChange} .../>
That handler will receive the index of the item the view changes too. In handleLightBoxViewChange call setState to update selectedImage:
handleLightBoxViewChange = (newIndex) => {
this.setState(state => ({
selectedImage: state.awsApiData[newIndex]
}));
};
If you don't wish to update the state, your footer component receives the current view so you could update it like this:
<LightBox
components={{
FooterCaption: ({currentView}) => <div>{currentView.title}</div>
}}
//...
/>