Table of contents
No headings in the article.
In this project, I am displaying a list of all my GitHub repositories and a details page for each repo. Here are the key features of the app. I also implemented error boundary to catch javascript errors within the app.
Pagination
SEO
Error Boundary
API fetch
Nested Routes
404 page
First I initialized a new project using the create-react-app command, next I installed all the necessary packages I need to build the app.
react-helmet-async // to implement SEO
react-router-dom // for routing and nested routes
node-sass // I use scss for syling
react-icons // icons library
To get the list of repos, I sent a GET request to
`https://api.github.com/users/mo-renike/repos?sort=${sort.sort}&direction=${sort.order}&per_page=100`
// mo-renike is my github username
//I had set the sort and order states to be dynamic
// const [sort, setSort] = useState({
// sort: "created",
// order: "desc",
// });
The response sent to me in JSON format as seen below. You can check the endpoint here https://api.github.com/users/mo-renike/repos
0
:
{id: 582022522, node_id: 'R_kgDOIrD1eg', name: 'portfolio', full_name: 'mo-renike/portfolio', private: false, …}
1
:
{id: 580917524, node_id: 'R_kgDOIqAZFA', name: 'nest-app', full_name: 'mo-renike/nest-app', private: false, …}
2
:
{id: 573953868, node_id: 'R_kgDOIjXXTA', name: 'methcreate', full_name: 'mo-renike/methcreate', private: false, …}
3
:
{id: 562556135, node_id: 'R_kgDOIYfs5w', name: 'zc_main', full_name: 'mo-renike/zc_main', private: false, …}
4
:
{id: 560920897, node_id: 'R_kgDOIW75QQ', name: 'ALTSch-FE-Exam', full_name: 'mo-renike/ALTSch-FE-Exam', private: false, …}
Here is how I choose to display the data
Each repo has an onClick function that links to a details page to get more information about the selected repo. To implement this, I used nested route and useParams to get the id of the selected repo. To get the details of the the repo I sent a new request to
`https://api.github.com/repos/mo-renike/<repoID>`
I build the details page using this data like this
To implement Pagination, first I set the number of repos to be displayed according to the page size. (this is a UX feature to prevent long scrolling for mobile devices)
// set dynamic reposPerPage value according to screen size
if (window.innerWidth <= 768) {
var dynamicPerPage = 3;
} else {
dynamicPerPage = 6;
}
const [currentPage, setCurrentPage] = useState(1);
const [reposPerPage] = useState(dynamicPerPage);
const indexOfLastRepo = currentPage * reposPerPage;
const indexOfFirstRepo = indexOfLastRepo - reposPerPage;
const currentRepos = repos.slice(indexOfFirstRepo, indexOfLastRepo);
// paginate function to set the pages when ou click the buttons
const paginate = (pageNumber) => {
setCurrentPage(pageNumber);
window.scrollTo({ top: 0, behavior: "smooth" });
};
// function to calculate page numbers
const pageNumbers = [];
for (let i = 1; i <= Math.ceil(repos.length / reposPerPage); i++) {
pageNumbers.push(i);
}
Implementing SEO was pretty straightforward using react-hemet-async
// first import package from the library
import { Helmet } from "react-helmet-async";
<Helmet>
<title>Repos</title>
<meta name="description" content="Github Repos" />
<meta
name="keywords"
content="altschool, github api,SEO, react hooks,"
/>
</Helmet>