Refactoring a React Photo Gallery - 2022-11-13

Refactoring & creating modern functionality on a React photo gallery

As I was working to update and add some photos on a clients website, specifically a photo gallery of their projects, when I came across a TODO in my documentation regarding the photo gallery.

TODO: Refactor / modernize gallery; with onClick? carousel/scroll?

So I was at a crossroads, as of now, the photo gallery is exactly what they are looking for and they love how it looked. Do I take the time and make it better? OF COURSE, why not complicate my afternoon...

So I set out to make this better. I wanted a click feature to open the image and I wanted to be able to scroll through the pictures without having to close and open each photo.

Luckily, there is always a great NPM package to be used. In my case I found 2 that work well with each other

  • react-images

  • react-photo-gallery

Here is my gallery component

function PhotoGallery() { const [currentImage, setCurrentImage] = useState(0); const [viewerIsOpen, setViewerIsOpen] = useState(false); const openLightbox = useCallback((event, { photo, index }) => { setCurrentImage(index); setViewerIsOpen(true); }, []); const closeLightbox = () => { setCurrentImage(0); setViewerIsOpen(false); }; return ( <> <Grid container direction="column"> <Gallery photos={photos} onClick={openLightbox} /> </Grid> <Box> <ModalGateway> {viewerIsOpen ? ( <Modal onClose={closeLightbox}> <Carousel currentIndex={currentImage} views={photos.map((x) => ({ ...x, srcset: x.srcSet, caption: x.title, }))} /> </Modal> ) : null} </ModalGateway> </Box> </> ); } export default PhotoGallery;

Let me explain my thought process.

Component State

// The current selected index / image position in the list of images in the gallery const [currentImage, setCurrentImage] = useState(0); // Flag to track if the modal is open or closed const [viewerIsOpen, setViewerIsOpen] = useState(false);

Methods

  • After spending sometime troubleshooting rendering / onclick bugs, I decided to go with the useCallback hook to prevent the function from being recreated unless necessary.

    Quick Note: I am still working to master "advanced" hooks. So, I wanted explain the difference between useMemo & useCallBack because they are similar.

    The main difference is that useMemo returns a memoized value and useCallback returns a memoized function.

    My understanding of memoization is basically caching a value so that it does not need to be recalculated until you need it.

// The onClick function for each image, which will open the modal, and will darken the background. const openLightbox = useCallback((event, { photo, index }) => { setCurrentImage(index); setViewerIsOpen(true); }, []); // Setting the modal flag, and clearing the image tracked image index. const closeLightbox = () => { setCurrentImage(0); setViewerIsOpen(false); };

Render Method

For this project I am using the Material UI component library v5.5.3. I didn't include the styles because I am lazy, so style with your imagination :)

return ( <> <Grid container direction="column"> /* photos is a json file of all images EXAMPLE JSON photos: [{ src: "img/path/imageName.jpg", // or whatever extension you have width: X, // customized width specific to the image height: X, // customized height specific to the image }], */ // Gallery component will display all images with the onClick method for each. <Gallery photos={photos} onClick={openLightbox} /> </Grid> <Box> // ModalGateway will insert the modal just before the end of the <body /> tag. <ModalGateway> // Conditional rendering of the modal, based on the state of the current modal flag. {viewerIsOpen ? ( <Modal onClose={closeLightbox}> <Carousel currentIndex={currentImage} views={photos.map((x) => ({ ...x, srcset: x.srcSet, caption: x.title, }))} /> </Modal> ) : null} </ModalGateway> </Box> </> );

Thats it! The creators of these packages make it super simple to use but if you need more information (like what other props these components take) here is what I used. Good Luck!

  • Official react-image documentation

  • Official react-photo-gallery documentation

  • Another step by step example

  • React useCallBack documentation

Buy Me A Coffee