It took me a while to even understand that it was happening on any parents state change. This causes visual artifacts.
function ImageGallery(props) {
const [currentIndex, setCurrentIndex] = useState(0);
const Direction = props.LTR === undefined ? true : props.LTR;
const translateStr = Direction ? "translateX(" : "translateY(";
const [height, setHeight] = useState(0);
const [width, setWidth] = useState(0);
useEffect(() => {
console.log("Imagegallery mounted.");
// Set size of image gallery to the largest image given.
if (props.w === undefined) {
setWidth(Math.max(...(props.srcs.map(o => { return o.w }))))
}
else {
let biggestWidth = Math.max(...(props.srcs.map(o => { return o.w })));
if (biggestWidth > props.w) {
setWidth(biggestWidth);
}
else {
setWidth(props.w);
}
}
if (props.h === undefined)
setHeight(Math.max(...(props.srcs.map(o => { return o.h }))))
else {
let biggestHeight = Math.max(...(props.srcs.map(o => { return o.h })));
if (biggestHeight > props.h) {
setHeight(biggestHeight);
}
else {
setHeight(props.h);
}
}
return ()=>{console.log("Image gallery dismounted.")}
}, [props]); // eslint-disable-line react-hooks/exhaustive-deps
return (
<div className="overflow-hidden position-relative mx-auto"
style={{
"width": width ? (width + "px") : "",
"height": height ? (height + "px") : "",
"backgroundImage": `${props.bgPath ? "url(" + props.bgPath + ")" : ""}`
}}>
{
props.srcs.map((imgProperties, index) => {
return (
<img key={imgProperties.path} className="galleryPhoto mx-auto my-auto"
height={imgProperties.h ?? height}
width={imgProperties.w ?? width}
src={imgProperties.path}
alt={imgProperties.alt}
style=
{{
"transform": translateStr + -((currentIndex - index) *
(Direction ? width : height)
) + "px)",
"left": ((width - imgProperties.w) * 0.5) + "px",
"top": ((height - imgProperties.h) * 0.5) + "px"
}}
/>
)
})
}
{/* TODO: add buttons going up and down for LTR == false*/}
<div className="GalleryControls user-select-none">
<div className={`galleryButton leftGal px-2 d-flex align-items-center ${currentIndex === 0 ? "greyedOutGalButton" : ""}`} onClick={() => {
if (currentIndex > 0) {
setCurrentIndex(currentIndex - 1);
}
}}>
<
</div>
<div className={`galleryButton rightGal px-2 d-flex align-items-center ${currentIndex === props.srcs.length - 1 ? "greyedOutGalButton" : ""}`} onClick={() => {
if (currentIndex < props.srcs.length - 1 && props.srcs.length > 1) {
setCurrentIndex(currentIndex + 1);
}
}}>
>
</div>
</div>
</div>
)
}
export default ImageGallery;
For reference, the CSS is below.
.galleryPhoto {
position:absolute;
left:0px;
top:0px;
transition: 0.5s ease;
}
.GalleryControls{
position:relative;
width:100%;
height:100%;
transition: 0.2s ease;
}
.galleryButton{
position:absolute;
background:rgba(48, 48, 48, 0.15);
transition:0.15s ease;
height:100%;
color:#ffffff;
font-size:1.2em;
}
.leftGal{
left:0px;
}
.rightGal{
right:0px;
}
@media screen and (min-width:768px){
.leftGal{
transform:translateX(-100%);
}
.rightGal{
transform:translateX(100%);
}
.GalleryControls:hover{
background:#FEFEFE14;
}
}
.GalleryControls:hover > .leftGal {
transform:translateX(0px);
}
.GalleryControls:hover > .rightGal {
transform:translateX(0px);
}
.greyedOutGalButton{
opacity:30%;
}
I know that there is a component on the market called react-image-gallery, but I didn't know that at the time of writing and I like my component. Just unsure as to why it remounts.
For easy use of this component, pass the props srcs
which contains an array of objects, each with at least a h
, w
and path
attribute.
Example is given below.
<ImageGallery h="360" w="360" bgPath="any360x360image.png" srcs={[
{path: "epicImage.png", h: 312, w: 312},
{path: "epicImage2.png", h: 360, w: 360},
{path: "epicImage3.png", h: 257, w: 270}]}
/>
When you run the code all together, it calls the useEffect upon any state change of the parent of the ImageGallery, and for every ImageGallery instance under its wing.