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.
For this tutorial, use this Image Collage Base code as your starting point to build your project upon.
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.
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.
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.
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.
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.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!