0

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);
                    }
                }}>
                    &lt;
                </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);
                    }
                }}>
                    &gt;
                </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.

  • 1
    I'm not 100% sure how you'd want to refactor this, but setting a state change inside a `useEffect` hook will trigger a re-render. – PsiKai Oct 23 '21 at 18:04
  • 1
    I think you pass a new srcs array every time. Check these to find out why a component re-renders: https://stackoverflow.com/a/51082563/4512646 – K41F4r Oct 23 '21 at 18:19
  • I do believe that the "new srcs array" answer is the right one, and thanks for the tip on refactoring - I have already fixed the fact that I'm directly trying to grab the props in the function body... Thanks guys. I'll check if that fixes it tomorrow or later and give you credit - please post as an answer if you want points. – peanutbatterballs Oct 23 '21 at 21:55

0 Answers0