REST Countries API challenge solved with Chakra UI and React.
Tags: javascript, chakraui, react, frontendmentor
Published: 2022-08-05 05:18:59

```

```
##Introduction
In this article, I will explain how I solved the Frontend mentor "REST Countries API with a color theme switcher" challenge using Chakra UI and Create React App. At the end of this tutorial, we should be able to 

1. See all countries from the [API](https://restcountries.com/)  on the homepage

2. Search for a country using an input field

3. Filter countries by region

4. Click on a country to see more detailed information on a 
   separate page

5. Click through to the border countries on the detail page

6. Toggle the color scheme between light and dark mode 
   (optional)

##Prerequisite
To follow this tutorial, you should have a basic understanding of the following.

1. Basic knowledge of JavaScript ES6 syntax and features

2. The basics of [ReactJS](https://create-react-app.dev/) terminology: JSX, State, Asynchronous 
   JavaScript, etc.
3. Basic understanding of Restful APIs.

4. Basic knowledge of [TypeScript](https://www.typescriptlang.org/)

5. Basic understanding of [Chakra UI](https://chakra-ui.com/)
6. Basic knowledge of [React Router](https://reactrouter.com/)

### Demo and Github Links
[Solution on Github](https://github.com/femakin/Frontend-Mentor-REST-Countries-APITask)
[Live site](https://countriesupdate.netlify.app/)

**Component breakdown**
1. Header Component
2. Home Component
3. Singlepage Component


##Setup
Before building each component, we start by creating a new create-react-app project from a template using Chakra UI automatic typescript template, as in the code below.

```
# TypeScript using npm
npx create-react-app my-app --template @chakra-ui/typescript
```

This command will bootstrap the bare-bones react app that is ready to use.
After creating our app, our folder structure should look like what we have in the image below.



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7lg2l77igpoux251cvg4.png)


Now, we navigate into the my-app folder and start our app by running `npm start`. We should have something that looks like the image below.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x2wefkke5vn4r21o2xzy.png)

 
###Removing unwanted CSS 

Now that we have generated a create-react-app project using a template, all we need to do is start creating our components and clean up the files.
Within the src folder, I have created two new folders: `pages` and `components`. 



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6izfh814s0j1k5vwk1f1.png)

###Packages
In addition to our pre-installed packages from create-react-app typescript templates, we will install additional two other packages that are

#### React-Router: 
This will help us with routing within our app. 
#### ChakraIcons: 
This will provide a set of commonly used interface icons you can use in our project.

We can now navigate into our root folder and run the code below so you can install both packages together.


```
npm install react-router-dom@6 @chakra-ui/icons

```


### Navlink component

Here, we use a Chakra UI Navbar template with a user dropdown and a Dark theme switcher.
```javascript
import {
  Box,
  Flex,
  Button,
  useColorModeValue,
  Stack,
  useColorMode,
} from '@chakra-ui/react';
import { MoonIcon, SunIcon } from '@chakra-ui/icons';
import { useNavigate } from 'react-router-dom';
export default function Nav() {
  const { colorMode, toggleColorMode } = useColorMode();
  let navigate = useNavigate();
  return (
    <>
      <Box bg={useColorModeValue('gray.100', 'gray.900')} px={4}>
        <Flex h={16} alignItems={'center'} justifyContent={'space-between'}>
          <Box onClick={()=> navigate('/')}  >Where in the world?</Box>
          <Flex alignItems={'center'}>
            <Stack direction={'row'} spacing={7}>
              <Button onClick={toggleColorMode}>
                {colorMode === 'light' ? <MoonIcon /> : <SunIcon />}
              </Button>
            </Stack>
          </Flex>
        </Flex>
      </Box>
    </>
  );
}
```
For this component, we are using ReactRouter for easy routing and chakra-UI/icons to access Chakra UI Icons.

### Routing:

Here, we link our components to the appropriate pages.
```javascript
import React from 'react'
import {Route, Routes } from "react-router-dom";
import Home from '../Pages/Home';
import SingleCountry from '../Pages/SingleCountry';


function Routing() {
  return (
    <div>
        <Routes>
        <Route path="/" element={<Home/>} />
        <Route path="/singlecountry/:countryname" element={<SingleCountry/>} />
      </Routes> 
    </div>
  )
}

export default Routing
```


Now that we have our navbar and routing components, we move to create our Homepage file

### Home:

```javascript
// Importing 
import React from "react";
import { useState, useEffect } from "react";
import {
  Flex,
  GridItem,
  Image,
  Input,
  InputGroup,
  InputLeftElement,
  Select,
  SimpleGrid,
  Spacer,
} from "@chakra-ui/react";
import { Box } from "@chakra-ui/react";
import { useNavigate } from "react-router-dom";
import { Progress } from "@chakra-ui/react";
import { SearchIcon } from "@chakra-ui/icons";
import Nav from "../Components/Navlink";

function Home() {

  //States
  const [data, setData] = useState([]);
  const [data2, setData2] = useState([]);
  const [searchInput, setSearchInput] = useState("");
  const [selectInput, setSelectInput] = useState("all");
  let navigate = useNavigate();


//Calling Apis
  useEffect(() => {
    if (selectInput === "all") {
      fetch(`https://restcountries.com/v3.1/all`)
        .then((res) => res.json())
        .then((data) => {
          return (
            setData(data),
            setData2(data))
        })
        .catch((err) => console.log("Error:", err.message));
    } else {
      fetch(`https://restcountries.com/v3.1/region/${selectInput}`)
        .then((res) => res.json()).then((data)=>{
          return (
            setData(data), 
            setData2(data)
          )
        })
        .catch((err) => console.log("Error:", err.message));
    }
  }, [selectInput]);


  //Handle Region select
  const handleChangeSelect = (e) => {
    setSelectInput(e.target.value);
  };

  //Handle Country Search
  const handleChangeInput = (e) => {
    e.preventDefault();
    setSearchInput(e.target.value);
    setData(
      data2.filter((x) =>
        x?.name?.common
          ?.toLowerCase()
          ?.includes(e?.target?.value?.toLowerCase())
      )
    );
  };

  return (
    <div>
      {/* Navbar */}
      <Nav/>
{/* 
    Country Search and Region Select form */}
      <form>
        <Flex pr="50" pl="50" flexWrap={"wrap"}>
          <Box p="4">
            <InputGroup>
              <InputLeftElement
                pointerEvents="none"
                children={<SearchIcon color="gray.300" />}
              />
              <Input
                value={searchInput}
                onChange={handleChangeInput}
                type="text"
                placeholder="Search for a country "
              />
            </InputGroup>
          </Box>
          <Spacer />
          <Box p="4">
            <Select onChange={handleChangeSelect} placeholder="Select option">
              <option value="all">All</option>
              <option value="africa">Africa</option>
              <option value="americas">Americas</option>
              <option value="asia">Asia</option>
              <option value="europe">Europe</option>
              <option value="oceania">Oceania</option>
            </Select>
          </Box>
        </Flex>
      </form>

      {/* Data Rendering */}

      {data2?.length === 0 ? (
        <Progress colorScheme="pink" size="xs" isIndeterminate />
      ) : (
        <Box w="100%">
          <SimpleGrid
            columns={[1, null, 4]}
            spacing={10}
            pt="100"
            pr="50"
            pl="50"
          >
            {data?.map((x) => (
              <GridItem
                key={x?.name?.common}
                onClick={() =>
                  navigate(`/singlecountry/${x?.cca2?.toLowerCase()}`, {})
                }
              >
                <Box
                  maxW="sm"
                  borderWidth="1px"
                  borderRadius="lg"
                  overflow="hidden"
                >
                  <Image
                    src={x?.flags?.svg}
                    alt={x?.name?.common}
                    height="200px"
                    width="100%"
                  />
                  <Box p="6">
                    <Box
                      mt="1"
                      fontWeight="semibold"
                      as="h4"
                      lineHeight="tight"
                      noOfLines={1}
                    >
                      {x?.name?.common}
                    </Box>

                    <Box
                      mt="1"
                      fontWeight="semibold"
                      as="h4"
                      lineHeight="tight"
                      noOfLines={1}
                    >
                      Population: {x?.population}
                    </Box>

                    <Box
                      mt="1"
                      fontWeight="semibold"
                      as="h4"
                      lineHeight="tight"
                      noOfLines={1}
                    >
                      Region: {x?.region}
                    </Box>

                    <Box
                      mt="1"
                      fontWeight="semibold"
                      as="h4"
                      lineHeight="tight"
                      noOfLines={1}
                    >
                      Capital: {x?.capital}
                    </Box>
                  </Box>
                </Box>
              </GridItem>
            ))}
          </SimpleGrid>
        </Box>
      )}
    </div>
  );
}

export default Home;

```
As you can see, there are a lot of lines of code to comprehend at once, so let's take it one step at a time.

#### Importing all the necessary components

Here, We import Flex, grid, item, Image, Input, InputGroup, InputLeftElement,Select,SimpleGrid,Spacer,Box, Progress from Chakra UI, use navigate from react-router, SearchIcon from ChakraIcons, and Nav from our Navlinks component

```javascript
// Importing 
import React from "react";
import { useState, useEffect } from "react";
import {
  Flex,
  GridItem,
  Image,
  Input,
  InputGroup,
  InputLeftElement,
  Select,
  SimpleGrid,
  Spacer,
  Box,
  Progress
} from "@chakra-ui/react";
import { useNavigate } from "react-router-dom";
import { SearchIcon } from "@chakra-ui/icons";
import Nav from "../Components/Navlink";
```
#### States:
We declared our states here
```javascript
  //States
  const [data, setData] = useState([]);
  const [data2, setData2] = useState([]);
  const [searchInput, setSearchInput] = useState("");
  const [selectInput, setSelectInput] = useState("all");
  let navigate = useNavigate();
```
#### Api:
Calling Api

```javascript

//Calling Apis
  useEffect(() => {
    if (selectInput === "all") {
      fetch(`https://restcountries.com/v3.1/all`)
        .then((res) => res.json())
        .then((data) => {
          return (
            setData(data),
            setData2(data))
        })
        .catch((err) => console.log("Error:", err.message));
    } else {
      fetch(`https://restcountries.com/v3.1/region/${selectInput}`)
        .then((res) => res.json()).then((data)=>{
          return (
            setData(data), 
            setData2(data)
          )
        })
        .catch((err) => console.log("Error:", err.message));
    }
  }, [selectInput]);

```
#### Region selection and Country Search functions
```javascript
  //Handle Region select
  const handleChangeSelect = (e) => {
    setSelectInput(e.target.value);
  };

  //Handle Country Search
  const handleChangeInput = (e) => {
    e.preventDefault();
    setSearchInput(e.target.value);
    setData(
      data2.filter((x) =>
        x?.name?.common
          ?.toLowerCase()
          ?.includes(e?.target?.value?.toLowerCase())
      )
    );
  };

```

#### Import Navbar 
```javascript
    
      <Nav/>

    Country Search and Region Select form 
      <form>
        <Flex pr="50" pl="50" flexWrap={"wrap"}>
          <Box p="4">
            <InputGroup>
              <InputLeftElement
                pointerEvents="none"
                children={<SearchIcon color="gray.300" />}
              />
              <Input
                value={searchInput}
                onChange={handleChangeInput}
                type="text"
                placeholder="Search for a country "
              />
            </InputGroup>
          </Box>
          <Spacer />
          <Box p="4">
            <Select onChange={handleChangeSelect} placeholder="Select option">
              <option value="all">All</option>
              <option value="africa">Africa</option>
              <option value="americas">Americas</option>
              <option value="asia">Asia</option>
              <option value="europe">Europe</option>
              <option value="oceania">Oceania</option>
            </Select>
          </Box>
        </Flex>
      </form>
```
#### Data Rendering

```javascript

 {data2?.length === 0 ? (
        <Progress colorScheme="pink" size="xs" isIndeterminate />
      ) : (
        <Box w="100%">
          <SimpleGrid
            columns={[1, null, 4]}
            spacing={10}
            pt="100"
            pr="50"
            pl="50"
          >
            {data?.map((x) => (
              <GridItem
                key={x?.name?.common}
                onClick={() =>
                  navigate(`/singlecountry/${x?.cca2?.toLowerCase()}`, {})
                }
              >
                <Box
                  maxW="sm"
                  borderWidth="1px"
                  borderRadius="lg"
                  overflow="hidden"
                >
                  <Image
                    src={x?.flags?.svg}
                    alt={x?.name?.common}
                    height="200px"
                    width="100%"
                  />
                  <Box p="6">
                    <Box
                      mt="1"
                      fontWeight="semibold"
                      as="h4"
                      lineHeight="tight"
                      noOfLines={1}
                    >
                      {x?.name?.common}
                    </Box>

                    <Box
                      mt="1"
                      fontWeight="semibold"
                      as="h4"
                      lineHeight="tight"
                      noOfLines={1}
                    >
                      Population: {x?.population}
                    </Box>

                    <Box
                      mt="1"
                      fontWeight="semibold"
                      as="h4"
                      lineHeight="tight"
                      noOfLines={1}
                    >
                      Region: {x?.region}
                    </Box>

                    <Box
                      mt="1"
                      fontWeight="semibold"
                      as="h4"
                      lineHeight="tight"
                      noOfLines={1}
                    >
                      Capital: {x?.capital}
                    </Box>
                  </Box>
                </Box>
              </GridItem>
            ))}
          </SimpleGrid>
        </Box>
      )}

```
### Single Country Component



Now, we create the single country component.

When a user clicks on a country, this is the single detailed information page that opens on a separate page. All we are doing here is setting our states and then updating the state with the response gotten from the API inside use effect. We then map our country state inside Chakra components.

```javascript
import React, { useEffect, useState } from "react";
import { useParams, useNavigate } from "react-router-dom";
import {
  Button,
  Center,
  GridItem,
  Image,
  Progress,
  SimpleGrid,
} from "@chakra-ui/react";
import { Box } from "@chakra-ui/react";
import Nav from "../Components/Navlink";


function SingleCountry() {
  let { countryname } = useParams();
  const [data, setData] = useState();
  let navigate = useNavigate();
  useEffect(() => {
    fetch(`https://restcountries.com/v3.1/alpha/${countryname}`)
      .then((res) => res.json())
      .then((data) => setData(data))
      .catch((err) => console.log("Error:", err.message));
  }, [countryname]);
  return (
    <div>
      <Nav />

      <Box onClick={() => navigate(-1)} p={'10'}  >
        <Button size="lg" variant="solid" mr="3">
          Back
        </Button>
      </Box>

      {data === undefined || data === null ? (
        <Progress colorScheme="pink" size="xs" isIndeterminate />
      ) : (
        data?.map((x) => {
          return (
            <Center key={x?.name?.common} >
              <SimpleGrid
                columns={[1, null, 2]}
                spacing={100}
                pt="100"
                pr="50"
                pl="50"
              >
                <GridItem w="100%">
                  <Image src={x?.flags?.svg} alt={x?.Region} height="350" />
                </GridItem>
                <GridItem w="100%">
                  <Box
                    mt="1"
                    fontWeight="semibold"
                    as="h4"
                    lineHeight="tight"
                    noOfLines={1}
                  >
                    {x?.name?.common}
                  </Box>

                  <SimpleGrid columns={2} spacing={10}>
                    <Box>Native Name: {x?.name?.common}</Box>
                    <Box>Top Level Domain: {x?.tld[0]}</Box>
                  </SimpleGrid>

                  <SimpleGrid columns={2} spacing={10}>
                    <Box>Population: {x?.population}</Box>
                    <Box>
                      Currencies:{" "}
                      {x?.currencies[Object?.keys(x?.currencies)[0]]?.name}
                    </Box>
                  </SimpleGrid>

                  <SimpleGrid columns={2} spacing={10}>
                    <Box>Region: {x?.region}</Box>
                    <Box>
                      Language(s): {x?.languages[Object.keys(x?.languages)[0]]}
                    </Box>
                  </SimpleGrid>

                  <SimpleGrid columns={2} spacing={10}>
                    <Box>Subregion: {x?.subregion}</Box>
                  </SimpleGrid>

                  <SimpleGrid columns={2} spacing={10}>
                    <Box>Capital: {x?.capital}</Box>
                  </SimpleGrid>

                  <SimpleGrid mt="50" columns={2} spacing={10}>
                    <Box>Border Countries:</Box>

                    <Box>
                      {x?.borders?.map((x) => (
                        <Button
                          onClick={() => navigate(`/singlecountry/${x}`)}
                          size="lg"
                          key={x}
                          variant="solid"
                          mr="3"
                        >
                          {x}
                        </Button>
                      ))}
                    </Box>
                  </SimpleGrid>
                </GridItem>
              </SimpleGrid>
            </Center>
          );
        })
      )}
    </div>
  );
}

export default SingleCountry;
```
Let’s create the heart of this project.

### App.tsx
```javascript
import * as React from "react"
import { ChakraProvider, theme } from '@chakra-ui/react'

import { BrowserRouter } from "react-router-dom";
import Routing from "./Components/Routing";

export const App = () => (
 <div>
<ChakraProvider theme={theme}>
<BrowserRouter>
<Routing/>
</BrowserRouter>
</ChakraProvider>

 </div>
)
```
Having created all our components, let's enter our app's directory and run `npm start` to start the app. At this point, we should see something like the image below.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vpasf3rmtrpbtld2zv4q.png)

At this point, if we click on any of the countries, it should route us to a different page where we can see more details about the country, like the image below.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lgroitoinlgzksd816od.png)

Well, congrats on that great hustle! You have the solution to REST Countries API with a color theme switcher ready at your disposal.

**Thanks for Reading🌟🎉**

It's great to see that you have enjoyed the article. Please, let me know what you think in the comment section.

On to another blog, some other day, till then Femi👋.