Tutorial

How To Build an Infinite Scroll Image Gallery with React and CSS Grid

React

While this tutorial has content that we believe is of great benefit to our community, we have not yet tested or edited it to ensure you have an error-free learning experience. It's on our list, and we're working on it! You can help us out by using the "report an issue" button at the bottom of the tutorial.

Introduction

In this tutorial, we will use the React frontend Javascript framework and CSS Grid to build an infinite scroll image gallery, using the Unsplash API to embed the photographic images. Using a codepen coding challenge from Scotch.io as a base for our code, we will use React.js to build out the interface, Axios to make the HTTP requests, and the react-infinite-scroll library to implement the infinite scroll feature.

Also, for this tutorial, we’ll employ React Hooks and use functional components throughout the project.

Prerequisites

For this tutorial, use this Image Collage Base code as your starting point to build your project upon.

Step 1 — Installing Required Packages

Import all required dependencies from a CDN. Codepen provides a search bar with which you can type in the name of the module, then select one from the result and add it to your project.

Dependencies installed are:

Go on to Unsplash to create an application and obtained an access key.

Step 2 — Building the Base Component

In React, the HTML template for the parent component is written in JSX. We shall proceed to write these HTML elements that make the template in JSX.

Create a functional component and render on the DOM with:

let Collage = () => {

    // Return JSX
  return (
    <div className="hero is-fullheight is-bold is-info">
      <div className="hero-body">
        <div className="container">
          <div className="header content">
            <h2 className="subtitle is-6">Code Challenge #16</h2>
            <h1 className="title is-1">
              Infinite Scroll Unsplash Code Challenge
            </h1>
          </div>
    // Images go here

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

// Render the component to the DOM element with ID of root
ReactDOM.render(<Collage />, document.getElementById("root"));

Here, you created the parent component Collage , returned the HTML elements in JSX, and rendered it in the DOM element with an ID of root. Bulma classes were used to provide basic styling of the page.

Step 3 — Building a Single Image Component

Next, let’s move on to creating a single component for a single fetched image. This will help us set the position of each image.

Create a single functional component with:

const UnsplashImage = ({ url, key }) => (
  <div className="image-item" key={key} >
    <img src={url} />
  </div>
);

This component receives props of url and key, which are the URL of the image to be displayed and the key for each rendered image. In the component, we use the <img/> element to display the fetched image.

Step 4 — Fetching and Rendering Random Images from Unsplash

Unsplash provides a free API to fetch random images. The images will be stored in a state container and passed to the DOM from state. Since we’ll use React Hooks, we’ll handle state and lifecycle methods with useState and useEffect, respectively.

In the Collage component, create two state variables, one to hold the incoming images and the other to store a boolean that tells the program if the images are loaded or not.

[...]

const [images, setImages] = React.useState([]);
const [loaded, setIsLoaded] = React.useState(false);

[...]

Next, we’ll create a function that fetches 10 random images using Axios. This is done by making a GET request to the API endpoint while passing your obtained access key and the amount of images you want returned. Do this with:

const fetchImages = (count = 10) => {
    const apiRoot = "https://api.unsplash.com";
    const accessKey = "{input access key here}";

    axios
      .get(`${apiRoot}/photos/random?client_id=${accessKey}&count=${count}`)
      .then (res => {
        setImages([...images, ...res.data]);
        setIsLoaded(true);
      });
};

Axios is a promise-based library, and on the resolution of the request, we use the setImages method to fill in the images fetched, as well as spread any previous images fetched. Also, we set the value of loaded to true.

Now that we have images stored in state, let’s call this fetchImages function once the component is mounted. In earlier versions of React, we would do this with the componentDidMount lifecycle method. However, React now provides the useEffect hook to handle all lifecycle operations in a functional component.

In the Collage component, call fetchImages on mount with:

[...]

React.useEffect(() => {
    fetchImages();
}, []);

[...]

The useEffect hook takes a second parameter, which is an array. The provided function in the hook will run every time the array is updated or modified.

Now you have a page that fetches ten random images from Unsplash. Let’s proceed to render the images in an infinite scroll container.

React-infinite-scroll-component provides the ability to display a loading spinner or any element as a placeholder, call a function to fetch more data once the loader is in view or approaches view, and displays any specified data. In the returned JSX of Collage and after the div with a class of header, render the images in the infinite scroll component with:

<InfiniteScroll
     dataLength={images}
     next={() => fetchImages(5)}
     hasMore={true}
     loader={
      <img
         src="https://res.cloudinary.com/chuloo/image/upload/v1550093026/scotch-logo-gif_jq4tgr.gif"
         alt="loading"
      />}
 >
     <div className="image-grid" style={{ marginTop: "30px" }}>
        {loaded ? 
            images.map((image, index) => (
                <UnsplashImage url={image.urls.regular} key={index} />
            )): ""}
    </div>
</InfiniteScroll>

In the InfiniteScroll component, we passed a function to the next parameter. The function calls the fetchImages function and passes a parameter of 5, which is the number of images to be fetched. In the loader parameter, we passed an image in JSX to serve as the loading placeholder.

.map() is used to iterate through the images array in state and renders each image using the UnsplashImage component.

We’ll use CSS grid to style the images fetched. Edit the CSS to this:

.title {
  font-family: 'Carter One';
}
.container {
  margin-top: 50px;
  text-align: center;
}

.image-grid {
  display: grid;
  grid-gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  grid-auto-rows: minmax(50px, auto);

  .image-item:nth-child(5n){
    grid-column-end: span 2;
  }

  img{
    display: flex;
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
}

This creates a grid with columns with a width of 250px and fills the entire image container. Also, the rows are set to have a minimum of 50px and a maximum of auto to fit each image. We used the grid-column-end property on every fifth image to make it take up two image spaces instead of one.

The object-fit property ensures each image fits or contains the full size of its container.

You can find the completed gallery here https://codepen.io/Chuloo/full/BMPXqy.

Conclusion

In this tutorial, we built out an image gallery using React hooks, as well as using CSS grid. You can try to play around with the grid to create an even better setup.

Creative Commons License