Creating an amazing Image search app using Unsplash API with infinite scrolling 📸

Learn Unsplash API, Axios and infinite scrolling!

Subscribe to my newsletter and never miss my upcoming articles

Listen to this article

Hello Folks 👋

This is Savio here. I'm young dev with an intention to enhance as a successful web developer. I love building web apps with React. I have proved my superiority in frontend technologies.

Today, I'm super pumped to build an amazing Image search app using Unsplash API with infinite scrolling. So, let's get started ✌


Table of contents

Setting up Unsplash API

  1. To set up Unsplash API for your app, head over to https://unsplash.com/developers and create an account scrnli_4_9_2021_11-00-46 AM.png

  2. After creating an account, go to your apps section. Here you could see your app. Now, create a new app by clicking New Application button. scrnli_08_04_2021_20-25-06.png

  3. Now accept all terms, this would create an app for you scrnli_08_04_2021_20-26-00.png

  4. You will be redirected to your app, here when you scroll you can see a section called Keys 🔑. Here you can see your access key, just save it for later. We are gonna use this. scrnli_08_04_2021_20-26-57.png

Let's Start Coding

So, it is time to get into coding our app. So, take your coffee and start coding! ⚡ First of all, let's create a react app by copy-pasting this code in the terminal.

npx create-react-app markdown-editor

Getting Into the project directory

cd markdown-editor/

Here are the dependencies that we use for our project 👩‍💻

  1. Axios
  2. react-infinite-scroll-component

Let's install all the dependencies using NPM.

npm i axios react-infinite-scroll-component

Starting our server ✨

npm start

Now we can see our app running in localhost:3000

welcome-to-react.png

Now, we can clear some unwanted files in our src/ folder. (this is optional). I am removing all the files except App.js, index.js and index.css. I am also clearing the default code.

So, let's first start with App.js. We can create 2 variables, this would help in fetching images using Unsplash API 📸

const client_id = "YOUR_ACCESS_KEY";
const fetchUrl = `https://api.unsplash.com/search/photos?client_id=${client_id}&query=${query}&page=${page}`;

and next we're setting some useState hooks.

const [data, setData] = useState([]);
const [query, setQuery] = useState("code");
const [page, setPage] = useState(1);
const [hasMore, setHasMore] = useState(true);

Now, create a function to fetch Images through Unsplash API. We are also gonna use axios that make the work faster. We are also increasing the page number after a load setPage(page + 1), this act important for infinite scrolling. Here goes the desired function 👇

const fetchImages = () => {
    axios
      .get(fetchUrl, {
        headers: {},
      })
      .then((response) => {
        setData([...data, ...response.data.results]);
      })
      .catch((error) => {
        console.log(error);
      });
    setPage(page + 1);
  };

Now, lets create a useEffect hook that would run whenever query is changed. Here goes the code 👇

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

Now, lets return all our components. It consists of a input and the InfiniteScroll wrapper. Inside InfiniteScroll wrapper, we map all images. 📷

return (
    <div className="App flex">
      <input
        type="text"
        onKeyDown={(e) => searchImages(e)}
        placeholder="Search For Images ğŸ”Ž"
      />
      <InfiniteScroll
        dataLength={data.length}
        next={fetchImages}
        hasMore={hasMore}
        loader={<p>Load more...</p>}
        endMessage={
          <p style={{ textAlign: "center" }}>
            <b>Yay! You have seen it all</b>
          </p>
        }
      >
        <div className="main flex">
          {data.map((data, key) => (
            <div className="container" key={key}>
              <img
                src={data.urls.small}
                className="image"
                alt={data.alt_description}
              />
              <h4>Photo by {data.user.name} 📸</h4>
            </div>
          ))}
        </div>
      </InfiniteScroll>
    </div>
  );

We also want to update our query on every enter click on the input. For that we're gonna use a new function.

const searchImages = (e) => {
    if (e.keyCode === 13) {
      setQuery(e.target.value);
      setData([]);
    }
  };

So, the work of App.js is finished. Here goes the complete code 👇

App.js

import axios from "axios";
import { useEffect, useState } from "react";
import InfiniteScroll from "react-infinite-scroll-component";
import "./App.css";

function App() {
  const [data, setData] = useState([]);
  const [query, setQuery] = useState("code");
  const [page, setPage] = useState(1);
  const [hasMore, setHasMore] = useState(true);

  const client_id = "4mB0CC1xdwTfTQGjF1v1uO9vS2Z8ubzBPd4X0B86IEU";
  const fetchUrl = `https://api.unsplash.com/search/photos?client_id=${client_id}&query=${query}&page=${page}`;

  const fetchImages = () => {
    axios
      .get(fetchUrl, {
        headers: {},
      })
      .then((response) => {
        setData([...data, ...response.data.results]);
      })
      .catch((error) => {
        console.log(error);
      });
    setPage(page + 1);
  };
  const searchImages = (e) => {
    if (e.keyCode === 13) {
      setQuery(e.target.value);
      setData([]);
    }
  };

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

  return (
    <div className="App flex">
      <input
        type="text"
        onKeyDown={(e) => searchImages(e)}
        placeholder="Search For Images ğŸ”Ž"
      />
      <InfiniteScroll
        dataLength={data.length}
        next={fetchImages}
        hasMore={hasMore}
        loader={<p>Load more...</p>}
        endMessage={
          <p style={{ textAlign: "center" }}>
            <b>Yay! You have seen it all</b>
          </p>
        }
      >
        <div className="main flex">
          {data.map((data, key) => (
            <div className="container" key={key}>
              <img
                src={data.urls.small}
                className="image"
                alt={data.alt_description}
              />
              <h4>Photo by {data.user.name} 📸</h4>
            </div>
          ))}
        </div>
      </InfiniteScroll>
    </div>
  );
}

export default App;

Now, our app is working but our app lacks beauty. So, lets style our app ğŸŽ¨.

App.css

@import url(https://fonts.googleapis.com/css?family=Poppins:100,100italic,200,200italic,300,300italic,regular,italic,500,500italic,600,600italic,700,700italic,800,800italic,900,900italic);

* {
  margin: 0;
  padding: 0;
  font-family: "Poppins", sans-serif;
}
body {
  background: #f5effc;
}
.App {
  flex-direction: column;
}
.image {
  width: 363px;
  border-radius: 5px;
  height: 240px;
}
.container {
  border-radius: 5px;
  margin: 5px;
  padding: 15px;
  box-shadow: 0 10px 40px -10px rgb(0 64 128 / 10%);
  border: 1px solid #eee;
  background: #f9fafc;
}
h4 {
  font-weight: 400;
}
.flex {
  display: flex;
  align-items: center;
  justify-content: center;
}
.main {
  width: 100%;
  height: 100%;
  flex-wrap: wrap;
}
input {
  padding: 10px;
  box-shadow: 0 10px 40px -10px rgb(0 64 128 / 10%);
  border: 1px solid #ddd;
  background: #f9fafc;
  width: 40%;
  margin: 15px 0;
}

Congrats ğŸŽ‰, You have now finished working on our app. Our app is now working perfectly as expected. You did it, it was so fast! Our app now looks like this 👇

Here is the code sandbox demo 💻

I have also deployed the app, Here goes the live demo 🚀 https://unsplash-image-search-app.vercel.app/

Here is the full source code, don't forget to star the repository 🌟 https://github.com/saviomartin/unsplash-image-search-app


👀 Wrapping Up

Yeah, that's a wrap. Hope you enjoyed the article. Do not hesitate to share your feedback. I am on Twitter @saviomartin7. Give a follow!

Follow me on Github @saviomartin, Don't miss my amazing projects! 💯

I hope you learned to use Unsplash API and created an image search app, now go start building amazing apps. Feedbacks are greatly appreciated! 🙌

Have an amazing day!

ğŸŒŽ Lets connect

🙌 Support

My projects are fueled by coffees ☕, get one for me!

Hrithwik Bharadwaj's photo

Thanks for the detailed explanation. Good Job Savio Martin

Savio Martin's photo

Thank you! Glad you enjoyed the article!

Edidiong Asikpo's photo

I love the final look of the project, Savio Martin and this article is also very well written. 🔥

Savio Martin's photo

Thank you Edidiong Asikpo, I'm so glad you enjoyed the work! 🔥

Varun Sridharan's photo

Good info :-)

Savio Martin's photo

Thank you! Glad you enjoyed the article! 💪

Lucky Victory Success's photo

Nice article, well explained. but I think it would be good not to show your client I'd.

Savio Martin's photo

Thank you Lucky Victory Success, I know it is not good to show client id in the app, I normally store them in .env files, I thought not to make the app more complex. It will make the app easier to understand. Thank you!