In this Media Jam, we will build an Image Gallery and use the Next.js Image component to optimize the images fetched from the Pexels API.
This gallery will show the list of curated photos by the Pexels team, and has a dynamic route to them. The users will also be able to search for images using this gallery.
You can play and explore the code described in this Jam on CodeSandbox. The code to display and search through the photos can be found in src/pages/index.js
. The src/pages/photos/[id].js
file contains the code to create dynamic routes for the pics.
To fetch the images, we will create a file named api.js
in the lib
directory. Inside this file, we will create a function to fetch the data using the fetch
method.
const API_KEY = process.env.NEXT_PUBLIC_PEXELS_API_KEY;
export const getCuratedPhotos = async () => {
const res = await fetch(
`https://api.pexels.com/v1/curated?page=11&per_page=18`,
{
headers: {
Authorization: API_KEY,
},
}
);
const responseJson = await res.json();
return responseJson.photos;
};
Code language: JavaScript (javascript)
If you take a closer look at the fetch URL, you will notice that we have added ?page=11&per_page=18
after the /curated
endpoint. These are the optional parameters that you can pass to the /curated
endpoint as query strings. Here page=11
means send the 11th page, and per_page=18
means that send 18 photos per page.
We will use the getServerSideProps()
function available in Next.js and use the getCuratedPhotos()
function inside it to fetch data from Pexels API and inject it in our page. You can read more about getServerSideProps()
here.
Add the following code at the bottom of your index.js
file:
export async function getServerSideProps() {
const data = await getCuratedPhotos();
return {
props: {
data,
},
};
Code language: JavaScript (javascript)
The above async function uses getCuratedPhotos()
to fetch images from the Pexels API and store them in the data
variable. This data
variable is made available as a prop in the props
property.
This data
is available as a prop, so add it as an argument in the Home
component function.
export default function Home({data}) {
const [photos, setPhotos] = useState(data);
...
}
Code language: JavaScript (javascript)
You could store the images in a React State named photos
, and then map over it to display the pictures using the img
element.
{
photos.map((pic) => (
<img src={pic.src.original} width="500" height="500" />
))
}
Code language: JavaScript (javascript)
A high definition image can range anywhere from 10MB to 100MB in size or more based on the image’s quality.
Imagine you have 80 images on your app’s landing page. Does it make sense to transfer around 800 MB of files every time someone visits your Gallery or website? It does not.
This is why today, most of the images on the web are served in WebP format. This format significantly reduces the size of the image, and you can hardly detect any visual difference.
So, we need to change the image format to webp
, but the question is, how? Do you need to do it manually? If yes, won’t it be time consuming and tiresome?
No, you don’t need to do it manually.
Next.js version 10 comes with built-in support for Image Optimization using the Image component. You can read more about this update here.
First, you need to import this component in index.js
.
import Image from "next/image";
Code language: JavaScript (javascript)
You will need to use this component to display the images instead of img
element.
{
photos.map((pic) => (
<Image
src={pic.src.portrait}
height={600}
width={400}
alt={pic.url}
/>
))
}
Code language: JavaScript (javascript)
You will also need to create a next.config.js
file to tell Next.js to trust the domain where the images are coming from. Add the following code to next.config.js
:
module.exports = {
images: {
domains: ["images.pexels.com"],
},
};
Code language: JavaScript (javascript)
This component will optimize the images fetched from Pexels.
The Next.js Image component has also added lazy loading to images. Here is an example to explain how and why you should use lazy loading if you are unfamiliar with it.
Even though the images are now in webp
format, is it necessary to load all the images whenever someone visits your website? And if the visitor just comes and leaves without scrolling, does it make sense to load the images at the bottom of the page?
There is no need to load the images that a user or visitor is not going to see in most situations.
And that’s where Lazy Loading comes to save the day. It delays the requests to images as to when they are needed, or in this situation, when images come into view. This helps to significantly reduce the initial page weight, and improves website performance.
If you head over to http://localhost:3000/ and scroll through all the images, you will see that the images that are not in the viewport are not loaded initially. But as you scroll down, they are transferred and loaded.
You could further develop this project and add other features and functionalities to it. Maybe you could start by adding animations, using Framer Motion!
Here are some additional resources that can be helpful: