React JS: Lab#RE01-2

React
Node.js
NPM
Spring Boot
Author

ProtossGP32

Published

April 19, 2023

Introduction

Link to class page

Main objectives:

  • We’ll be uusing our own RESTful API in SpringBoot to create a React app that will display a list of publications
  • We will use the Axios library to make HTTP requests to the API and retrieve the data in JSON format
  • We will display the publication data in a table with fields that will depend on the publication type
  • We will also add a loading state to show the user that the app is retrieving data from the API

The lab will demonstrate how to use a RESTful API with React to build a functional web application

Create the app

Follow the same steps as in the Lab-RE01-1 or simply clone the project into another directory.

Remember to install axios dependency inside the project.

Prepare the Spring Boot API

We’ll be using our Library Management Spring Boot API to retrieve any kind of resource, be it Publications, Users, Librarians, Authors, etc…

Leave it running while testing the React app.

Modify the app

BookList

Now the BookList component should request data from our SpringBoot API, so some things must be changed.

BookList.jsx
import React, { useState, useEffect } from 'react';
import axios from 'axios';

const BookList = () => {
    const [books, setBooks] = useState([]);
    const [isLoading, setIsLoading] = useState(true);

    // useEffect hook ensures that the BookList component stays connected to the SpringBoot API while displayed on the page
    useEffect(() => {
        // Define the fetchBooks function (?)
        const fetchBooks = async () => {
            const response = await axios.get(
                'http://localhost:9090/api/publications/books'
            );
            
            const booksData = response.data;
            setBooks(booksData);
            setIsLoading(false);

        };
        // Invoke the fetchBooks function
        fetchBooks();
        // TODO: return a clean code function with cleanup code that disconnects from the SpringBoot API

    }, []); // No dependencies required nor values from the component used inside of those functions

    return (
        <>
            <h1>Books</h1>
            {isLoading ? (
                <p>Loading...</p>
            ) : (
                <ul>
                    {books.map((book) => (
                        <li key={book.id}>
                            <strong>Title:</strong> {book.title} <br />
                            <strong>Year:</strong> {book.publicationDate} <br />
                            <strong>Author:</strong> {book.author.firstName + " " + book.author.lastName} <br />
                            <strong>ISBN:</strong> {book.isbn} <br />
                            <strong>Pages:</strong> {book.pages} <br />
                            <strong>Genre:</strong> {book.genre} <br />
                        </li>
                    ))}
                </ul>
            )}
        </>
    );
};

export default BookList;

Modify the Spring Boot API

Due to some restrictions related to CORS, we must modify our @RestController mappings to accept incoming requests from the React app. In order to do so, we’ll add the @CrossOrigin annotated followed by the origins parameter with the accepted URLs as values:

PublicationsRestController.java
package com.springbootlab0.approach_1.rest_controllers;

import com.springbootlab0.approach_1.domain.*;
import com.springbootlab0.approach_1.services.PublicationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("api/publications")
public class PublicationsRestController {

    @Autowired
    PublicationService publicationService;

    @CrossOrigin(origins = "http://localhost:3000")
    @GetMapping("all")
    public Iterable<Publication> getAllPublications() {
        return publicationService.getAllPublications();
    }

    @CrossOrigin(origins = "http://localhost:3000")
    @GetMapping("books")
    public Iterable<Publication> getAllBooks() {
        return publicationService.getAllBooks();
    }

    @PostMapping(value = "books/create", consumes = "application/JSON")
    public Publication createBook(@RequestBody Book book) {
        return publicationService.createPublication(book);
    }

    @CrossOrigin(origins = "http://localhost:3000")
    @GetMapping("cds")
    public Iterable<Publication> getAllCD() {
        return publicationService.getAllCDs();
    }

    @PostMapping(value = "cds/create", consumes = "application/JSON")
    public Publication createCD(@RequestBody CD cd) {
        return publicationService.createPublication(cd);
    }

    @CrossOrigin(origins = "http://localhost:3000")
    @GetMapping("dvds")
    public Iterable<Publication> getAllDVD() {
        return publicationService.getAllDVDs();
    }

    @PostMapping(value = "dvds/create", consumes = "application/JSON")
    public Publication createDVD(@RequestBody DVD dvd) {
        return publicationService.createPublication(dvd);
    }

}

For now, we’ll add http://localhost:3000 as our React app URL, but when going to production, these paths should be parametrized.

Adding CSS to ReactJS

Main objectives:

We’ll add some styling to the React app and use JavaScript to render objects in different fashions:

  • Grid
  • Card
  • Image
  • JavaScript

The lab will demonstrate how to use a RESTful API with React and use Components to render objects with CSS

Install dependencies

Install Semantic through npm

Install Semantic
npm install semantic-ui

Modify functions

Book

Book will provide the parameters of any stored book. Make sure that Spring Boot API provides the required information.

Do the same for the rest of publications

Same for CD and DVD

Person

Person will be used to provide the parameters of any LibraryManager. Make sure that Spring Boot API provides the required information.

Create new components

PersonCard

Go to Semantic CSS page and look for the Card component. Analyse what parameters the Card expects and make sure that the SpringBoot API provides them when requesting Books. Then, create your own PersonCard to format it with the available LibraryMember attributes:

src/Componets/PersonCard/index.jsx
import { Card, Image } from "semantic-ui-react";

// Props are spreaded prior to pass them to the PersonCard component
const PersonCard = ({image, firstName, lastName, birthDate, role}) => {
    return (
        <>
            <Card style={{ margin: "10px" }}>
                <Image src={image} wrapped ui={false} />

                {/* Define the Card contents */}
                <Card.Content>
                    <Card.Header>
                        {lastName}, {firstName}
                    </Card.Header>
                    <Card.Meta>Birthdate: {birthDate}</Card.Meta>
                    <Card.Description>{firstName} is a {role}</Card.Description>
                </Card.Content>
            </Card>
        </>
    );
};

export default PersonCard;