GitHub Data Fetch: How to Fetch your GitHub Profile and Repositories Using Reactjs and TailwindCSS.

GitHub Data Fetch: How to Fetch your GitHub Profile and Repositories Using Reactjs and TailwindCSS.

Table of contents

No heading

No headings in the article.

Hello there😃, I'm elated to write this article as it is my very first technical write-up and I am hoping this would help you navigate through your current project.

The goal of this article will be to fetch my Github profile and all repositories(including individual details) associated with my account using the GitHub public API. The data gotten will then be used to create a kind of Portfolio card and a repository list with Pagination implemented into it.

Before diving fully into this, you should be familiar and comfortable using with the following ;

  • Basic Javascript

  • Reactjs

  • API's

  • npm/yarn or any package installer

The first step in this project is to initialize a new react app which I will be doing using vite rather than the traditional CRA (create-react-app). I'm using vite because it's super fast, lightweight, and easy to use even for beginners.

To install and initialize a new react app, you just have to type this command in your terminal :

npm create vite

You will be directed to provide a name for your new project and to select a framework of Javascript you prefer to use(in this case react).

You should get something like this after the successful installation of react;

You can read more about installing react with vite here if you encounter any difficulty.

The next step is setting up a consistent route which will be done in the App.js file by installing react-router using the below command:

npm i react-router-dom

Then we set up our routes like this to link to the different pages (components) in our app. Dynamic routing is created for the repoData page to show the different repositories data according to the one clicked which is made possible by using the useParams hook made available by react-router

import { Routes, Route } from "react-router-dom";
import Home from "./components/Home";
import Layout from "./components/Layout";
import Repos from "./components/pages/Repos";
import RepoData from "./components/pages/RepoData";
import Error404 from "./components/pages/Error404";
import ErrorBoundary from "./components/ErrorBoundary";
import ErrorBoundaryTest from "./components/pages/ErrorBoundaryTest";

function App() {

  return (
          <Routes>
            <Route path="/">
              <Route element={<Layout />}>
                <Route index element={<Home />} />
                <Route path="repos" element={<Repos />} />
                <Route path="repos/:details" element={<RepoData />} />
                <Route path="/errorboundary" element={<ErrorBoundaryTest />} />
                <Route path="*" element={<Error404 />} />
              </Route>
            </Route>
          </Routes>
  );
}

export default App;

After setting up our routes, we have to fetch our Github repository data using the GitHub API. For that, we have to use the useState and useEffect hook by importing it directly from react. After that, we have to create a new state to manage and save the data fetched in the useEffect hook. Since we are going to need the data gotten from the API across all pages, we have to use the createContext hook from react to be able to share the state and then wrap all the route pages with a context.Provider and give a value to it(data to be shared). Your code should look like this now:

import {useEffect, useState, createContext } from "react";
import { Routes, Route } from "react-router-dom";
import Home from "./components/Home";
import Layout from "./components/Layout";
import Repos from "./components/pages/Repos";
import RepoData from "./components/pages/RepoData";
import Error404 from "./components/pages/Error404";
import ErrorBoundaryTest from "./components/pages/ErrorBoundaryTest";

export const RepoContext = createContext();

function App() {
  const [repos, setRepos] = useState([]);
  const [isLoading, setIsLoading] = useState(false);


  //   Fetching Lekanjoy Github Repositories
  useEffect(() => {
    setIsLoading(true);
    fetch("https://api.github.com/users/Lekanjoy/repos?per_page=100")
      .then((res) => res.json())
      .then((data) => {
        setRepos(data);
        setIsLoading(false);
      })
      .catch((err) => {
        console.error(err)
        alert('Please check your Internet connection âš ')
      });

  }, []);

  return (
        <RepoContext.Provider value={{ repos, isLoading }}>
          <Routes>
            <Route path="/">
              <Route element={<Layout />}>
                <Route index element={<Home />} />
                <Route path="repos" element={<Repos />} />
                <Route path="repos/:details" element={<RepoData />} />
                <Route path="/errorboundary" element={<ErrorBoundaryTest />} />
                <Route path="*" element={<Error404 />} />
              </Route>
            </Route>
          </Routes>
        </RepoContext.Provider>
  );
}

export default App;

The data shared across all pages display only the repository data, but we also need to generate a Profile card which will show the details of the Github user. To do that, we have to fetch the data differently and use the data gotten to populate the already created profile component. Two states are created, the first to save the data from the API, and the second one is a loading state to make the app user-friendly when there is a hold in fetching the data due to different issues (i.e poor connectivity)

import React, { useState, useEffect} from "react";
import Profile from "./Profile";
import ProfileSkeletonLoading from "./ProfileSkeletonLoading";

const Home = () => {

  const [portfolio, setPortfolio] = useState([]);
  const [isLoading, setIsLoading] = useState(false);

  // Fetching My GitHub Portfolio
  useEffect(() => {
    setIsLoading(true);
    fetch('https://api.github.com/users/lekanjoy')
      .then((res) => res.json())
      .then((data) => {
        setPortfolio(data);
        setIsLoading(false);
      })
      .catch((err) => console.error(err));
  }, []);

  return (
    <section className="px-8 bg-teal-50 min-h-[90vh] flex justify-center items-center">
      {isLoading === true ? (
        <ProfileSkeletonLoading />
      ) : (
        <Profile portfolio={portfolio} />
      )}
    </section>
  );
};

export default Home;

Since we now have access to the data from the GitHub API which shows all my repository data as a JSON, we can now use the data in our Repos component which was styled using Tailwind and map the data to dynamically generate each repository name and some other details we wish

We also have to give each repository a link, so that when clicked, .it would go to the repoData page to dynamically display further details of the repository. To do that, we import the Link from react-router and wrap the repo with it, then give the to prop in the link the unique id of each repo data gotten from the API to make sure that the particular repo being clicked will show the correct detail.

import { Link } from "react-router-dom";

const Repo = ({ repos }) => {
  return (
    <>
      {repos.map((repo) => {
        return (
          <div
            key={repo.id}
            className="repo bg-white w-full  text-center flex gap-x-2 justify-between items-center flex-col p-3 mb-3 rounded-md cursor-pointer shadow-lg duration-700 ease-in-out md:flex-row md:px-8 md:hover:scale-105"
          >
            <h2 className="font-semibold text-lg">{repo.name}</h2>
            <Link to={`/repos/${repo.id}`} className="bg-blue-400 w-full p-2 rounded-md text-white font-semibold mt-3 hover:bg-blue-300 md:mt-0 md:w-auto">
              View Details
            </Link>
          </div>
        );
      })}
    </>
  );
};

export default Repo;

If the above is done correctly, each repository should display correctly and when one is clicked it should redirect to the repoData page (which would show static detail data). To make sure the repoData page displays the correct detail data for each repository, we have to use the useContext hook in react to access the global data and also the useParam hook in react router.

We have to compare if the particular repository id clicked is the same as the dynamic route of the current page, if that is true, the repoData card which is styled will dynamically generate the data.

import React, {useContext} from 'react'
import { useParams} from "react-router-dom";
import { FaCodeBranch, FaStar, FaGithub } from "react-icons/fa";
import {RepoContext} from '../../App'
import fork from '../../assets/9026808_git_fork_thin_icon.png'


const RepoData = () => {
 const { details } = useParams();
 const { repos } = useContext(RepoContext);
 const repoDetails = repos.find((repo) => repo.id === parseInt(details));





  return (
    <section className="p-4 w-full bg-[#0d1017]  flex justify-center items-center min-h-[90vh]">
      <div className="w-full rounded-2xl border-2  flex justify-center text-[#c0c3ca] items-center flex-col  px-4 py-8 max-w-lg">
        <h1 className="font-bold text-2xl tracking-widest mb-1 text-center ">
          {repoDetails?.name}
        </h1>
        <p className="text-center mb-5 text-gray-500 text-sm">
          {repoDetails?.description}
        </p>
        <div className="flex gap-x-8">
          <p className="flex items-center gap-x-1">
            <img className='w-[20px]' src={fork} alt="GitHub fork icon" />
           : {repoDetails?.forks_count}
          </p>
          <p className="flex items-center gap-x-1">
            <FaStar className="text-[#c0c3ca]" />:{" "}
            {repoDetails?.stargazers_count}
          </p>
          <p className="flex items-center gap-x-1">
            <FaCodeBranch />: {repoDetails?.default_branch}
          </p>
        </div>
        <p className="mt-4">
          <span className="font-bold">Primary Language: </span>
          {repoDetails?.language}
        </p>
        <p className="font-bold text-sm mt-6 md:text-base">
          <span>Date Created: </span>
          {repoDetails?.created_at}
        </p>
        <a
          href={repoDetails?.html_url}
          className="bg-[#1F6FEA]  flex items-center justify-center gap-x-2
         text-white font-semibold mt-1 text-center rounded-md p-3 w-full hover:bg-blue-500"
        >
          <FaGithub /> View Code
        </a>
      </div>
    </section>
  );
}

export default RepoData;

All assets used in styling the app was imported locally but some modifications to the UI of the page were done by using react-icons to replace most assets in the app.

Thank you for reading this far and I hope I have helped a little in showing you to fetch your GitHub portfolio. Please feel free to leave a comment.

Â