We are going to build Google Bookshelf React App with the following components:
Parent component : AppBookShelf.jsx contains three child components – NavBar.jsx, BookList.jsx and Footer.jsx. The children components are put in components folder.
Child components in components folder :
NavBar.jsx: This component includes the application header title and the SearchBar.jsx, both located in the same directory.
BookList.jsx: This component is responsible for displaying a list of book information fetched from an API endpoint. It accepts props for the title, authors, description, and publisher, as well as additional query props.
Footer.jsx: Contains copyright information along with social media links for Instagram, YouTube, Facebook, and X.
The code for the AppBookShelf.jsx parent component
Step-by-Step Explanation for Students
Setup:
Import the required libraries and components.
Initialize the state variables using useState.
Fetch API Data:
Define fetchBooks to fetch and parse data from the Google Books API.
Handle errors gracefully.
React Lifecycle:
Use useEffect to ensure the API is called when the component loads or when query changes.
Handle User Input:
Define a function (handleSearch) to update the query based on user input.
Render the UI:
Divide the app into child components (NavBar, BookList, Footer) for better modularity.
Pass props to child components to maintain communication between them.
Layout Structure of AppBookShelf Component
// Layout Design of AppBookShelf Component
AppBookShelf Component
│
├── State
│ ├── books (useState) - Array of fetched books
│ └── query (useState) - Search query string, default: 'react'
│
├── Methods
│ ├── fetchBooks() - Async function to fetch books from Google Books API
│ └── handleSearch() - Updates query state with new search term
│
├── Effects
│ └── useEffect - Calls fetchBooks when query changes
│
└── Render Structure
└── <div> (container mt-5)
├── <NavBar> - Navigation component
│ ├── Props:
│ │ ├── query - Current search query
│ │ └── onSearch - handleSearch callback
│
├── <BookList> - Book display component
│ ├── Props:
│ │ ├── books - Array of book data
│ │ └── query - Current search query
│
└── <Footer> - Footer component
//Pareant component in src folder : AppBookShelf.jsx
// Import necessary libraries and hooks
import React, { useState, useEffect } from 'react';
import NavBar from './components/NavBar';
import BookList from './components/BookList';
import Footer from './components/Footer';
import 'bootstrap/dist/css/bootstrap.min.css';
const AppBookShelf = () => {
// Step 1: Initialize state variables
const [books, setBooks] = useState([]); // Stores fetched book data
const [query, setQuery] = useState('react'); // Default query for API
// Step 2: Fetch books from the API
const fetchBooks = async () => {
try {
const response = await fetch(`https://www.googleapis.com/books/v1/volumes?q=${query}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
setBooks(data.items || []); // Update state with fetched books or an empty array
} catch (error) {
console.error('Error fetching books:', error);
}
};
// Step 3: Use useEffect to trigger fetchBooks on mount or query change
useEffect(() => {
fetchBooks();
}, [query]);
// Step 4: Handle query updates from child components
const handleSearch = (newQuery) => {
setQuery(newQuery);
};
return (
<div className="container mt-5">
{/* Step 5: Render the NavBar with props */}
<NavBar query={query} onSearch={handleSearch} />
{/* Step 6: Render the BookList with fetched data and query */}
<BookList books={books} query={query} />
{/* Step 7: Render the Footer */}
<Footer />
</div>
);
};
export default AppBookShelf;
Explanation of Code Structure
App Structure
API End Point: https://www.googleapis.com/books/v1/volumes?q=${query}
Import Libraries and Components:
React: Core library for building UI.
useState and useEffect: Hooks for managing state and side effects.
Child Components: NavBar, BookList, and Footer for modularity.
State Management:
books: Holds the book data fetched from the API.
query: Stores the user's search term.
Fetching Data:
fetchBooks is an asynchronous function that retrieves book data from the Google Books API.
Updates the books state with the fetched results or an empty array if no data is returned.
Effect Hook:
Ensures fetchBooks runs when the component mounts or the query state changes.
Handle Search:
handleSearch is a function that updates the query based on user input received from the NavBar component.
Child Components:
NavBar: Contains the search bar and passes the query handling logic.
BookList: Receives books and query as props and displays book data.
Footer: Displays copyright and social media links.
Bootstrap Integration:
Styling is done using Bootstrap classes for a professional look.
Explanation of AppBookShelf.jsx Code Structure and Snippets
The code is structured step-by-step to make it easy for students to understand how the parent component manages data and communicates with its child components. Here's a detailed breakdown:
1. Importing Libraries and Components
import React, { useState, useEffect } from 'react';
import NavBar from './components/NavBar';
import BookList from './components/BookList';
import Footer from './components/Footer';
import 'bootstrap/dist/css/bootstrap.min.css';
React: Core library for creating React components.
useState and useEffect: Hooks for managing state and side effects.
Child Components:
NavBar: Contains the search bar and header.
BookList: Displays the list of books.
Footer: Contains footer content (e.g., copyright and social links).
Bootstrap: A CSS framework for styling the app.
2. State Management
const [books, setBooks] = useState([]); // Stores the fetched book data
const [query, setQuery] = useState('react'); // Default search query
books:
Stores the array of books fetched from the API.
Initially set to an empty array.
query:
Stores the search term entered by the user.
Defaults to "react" to show results when the app first loads.
3. Fetching Data from the API End Point
const fetchBooks = async () => {
try {
const response = await fetch(`https://www.googleapis.com/books/v1/volumes?q=${query}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
setBooks(data.items || []); // Update books state with fetched data
} catch (error) {
console.error('Error fetching books:', error);
}
};
API Endpoint:
Fetches book data using the search term stored in query.
Steps:
Makes an HTTP GET request using fetch.
Checks if the response is successful (response.ok).
Parses the response JSON and updates the books state.
Handles errors with try...catch.
4. Using useEffect for Side Effects
useEffect(() => {
fetchBooks();
}, [query]);
Purpose:
Automatically fetches data when the component mounts or when the query state changes.
Dependency Array:
[query] ensures the function re-runs only when the search term changes.
5. Handling Search Input
const handleSearch = (newQuery) => {
setQuery(newQuery); // Updates the query state with the new input
};
Functionality:
Called back when the user enters a new search term.
Updates the query state, which triggers useEffect to fetch new data.
6. Rendering the Component - NavBar, BookList, Footer components