React JS: Lab#RE02-1

React
Router
Hooks
API
axios
Training with Hooks and API HTTP requests
Author

ProtossGP32

Published

April 19, 2023

Introduction

Link to class page

React Router enables “client side routing”.

Client side routing allows your app to update the URL from a link click without making another request for another document from the server.

Main concepts of Router

Link

Getting started

Install dependencies

  • Router:
Installing Router dependency
npm install react-router-dom

Create the project directory structure

Project structure
src
├── App.css
├── App.js
├── App.test.js
├── components // Here we'll create each of the Hook examples
│   └── PersonCard
│       └── index.jsx
├── index.css
├── index.js
├── logo.svg
├── pages
│   ├── contact
│   │   └── Contact.jsx
│   ├── home
│   │   └── Home.jsx
│   └── people
├── reportWebVitals.js
├── route
│   ├── Footer.jsx
│   ├── Layout.jsx
│   └── NoPage.jsx
└── setupTests.js
TODO: Complete the lab

Adding components

Hooks

TODO: Transcribe the already coded hook examples here

API Rest

We’ll use the public API JSONPlaceHolder to access data through an API. We’ll use axios to send HTTP requests to the API.

Question: Why do we define the setData function as the useEffect dependency?

Install required packages

axios is a promise-based HTTP client for node.js and the browser.

  • It is isomorphic, meaning…
    • On the server-side it uses the native node.js HTTP module
    • On the client (browser) it uses XMLHttpRequests

We use the Axios library to fetch data from the JSONPlaceholder API, which provides a fake REST API for testing and prototyping.

Install axios using npm:

Installing axios package
npm install axios

Create the component

Let’s create a new component:

  • It’s project path will be: src/components/AxiosApiRest/index.jsx

Let’s start by initializing a state variable called data that will store the response received from the API:

const [data, setData] = useState([]);

A useState manages its state and sets data initial value to an empty array.

Let’s also set the API url as a constant:

const url = "https://jsonplaceholder.typicode.com/todos";

Now we’ll create a useEffect to fetch the data from the API and upate the data state variable when:

  • The component is mounted (on initialization time)
  • The setData function is called
useEffect(() => {
    // Configure the axios command to retrieve data from the API
    axios
        .get(url)
        // 'then' is executed only if data has been received from the GET request
        .then((response) => {
            // Assign the received data to the 'data' state variable -> This will trigger again the useEffect hook
            setData(response.data);
        })
        // If there's some kind of error on the GET request, catch it and print it as a console log
        .catch((error) => {
            console.log(error)
        });
}, [setData]); // Set 'setData' as a dependency of the useEffect to trigger it

This should act as a kind-of-recursive function, as the useEffect triggers itself again if a response is received from the GET request to the API.

Finally, return the HTML rendered component:

return (
    <>
        <h1>My data todos from axios</h1>
        { /* Only render this part if data is not empty */}
        { data &&
            data.map((item) => {
                return(
                    <spam key={item.id}>
                        id: {item.id}
                        <spam>userId:   {item.userId}</spam>
                        <spam>title:    {item.title}</spam>
                        <spam>completed:    {item.completed}</spam>
                        <br />
                    </spam>
                );
            })
        }
    </>
);

The final component should be something like this:

AxiosApiRest/index.jsx
import React, { useEffect, useState } from 'react';
import axios from 'axios';

export default function AxiosApiRest() {
    // Declare the 'data' state variable
    const [data, setData] = useState([]);
    // Define the REST API URL to request data from
    const url = "https://jsonplaceholder.typicode.com/todos";

    // Define the 'useEffect' that will fetch the data
    useEffect(() => {
        // Configure the axios command to retrieve data from the API
        axios
            .get(url)
            // 'then' is executed only if data has been received from the GET request
            .then((response) => {
                // Assign the received data to the 'data' state variable -> This will trigger again the useEffect hook
                setData(response.data);
            })
            // If there's some kind of error on the GET request, catch it and print it as a console log
            .catch((error) => {
                console.log(error)
            });
    }, [setData]); // Set 'setData' as a dependency of the useEffect to trigger it

    // Return the rendered component
    return (
        <>
            <h2>My data todos from axios</h2>
            { /* Only render this part if data is not empty */}
            { data &&
                data.map((item) => {
                    return(
                        <spam key={item.id}>
                            id: {item.id}
                            <spam>userId:   {item.userId}</spam>
                            <spam>title:    {item.title}</spam>
                            <spam>completed:    {item.completed}</spam>
                            <br />
                        </spam>
                    );
                })
            }
        </>
    );
}

Add a new page in src/pages/apirest/ApiRest.jsx pointing towards the component and the corresponding route to that page in the App.js:

src/pages/apirest/ApiRest.jsx
import React from 'react';
import AxiosApiRest from '../../components/AxiosApiRest';

function ApiRest() {
    return (
        <>
            <h1>API Rest examples</h1>
            <hr></hr>
            <AxiosApiRest />
        </>
    )
}

export default ApiRest;
src/App.js
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Layout from "./route/Layout.jsx";
import Home from "./pages/home/Home.jsx";
import HooksExamples from "./pages/hooksexamples/HooksExamples.jsx"
import Contact from "./pages/contact/Contact.jsx";
import NoPage from "./route/NoPage.jsx";
import ApiRest from "./pages/apirest/ApiRest.jsx";

function App() {
  // View with return JSX
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Layout />}>
          <Route index element={<Home />} />
          <Route path="hooksexamples" element={<HooksExamples />} />
          <Route path="apirest" element={<ApiRest />} />
          <Route path="contact" element={<Contact />} />
          <Route path="*" element={<NoPage />} />
        </Route>
      </Routes>
    </BrowserRouter>
  );
}

export default App;