ReactJS-The Beginner Master Class
  • React In the Beginning
    • Lesson 1 - Demo: Build a Simple React App - Fast
    • Lesson 2 - HTML Review
    • Lesson 3 - CSS Review
    • Lesson 4 - Modern JavaScript (JSX) Patterns
    • Lesson 5 - Set up Dev Environment
    • Hands-on Practice
  • React Fundamentals
    • Lesson 1 - Understanding Old vs New Way of Building Web Apps - SPAs
    • Lesson 2 - Motivation for Using React as the Solution to Vanilla JS
    • Lesson 3 - What is ReactJS - How it Works
    • React Code Along from Scratch
    • Lesson 4 - Create and Run a React Project with Vite - Full Overview
    • Lesson 5 - Create Hook by State Management in React
    • Lesson 6 - React Project File and Folder Walkthrough
    • Lesson 7 - JSX and How React Treats the DOM & JSX Compilation(by Babeljs) - Overview
    • Lesson 8 - Understanding the Main Files - App.jsx and main.jsx
    • Lesson 9 - Props and One-Way Data Flow - Overview
    • Lesson 10 - Google Bookshelf App - Ver 1.0
    • Hands-on Practice I
    • Hands-on Practice II
  • React State and Styling
    • Lesson 1 - Pulling Book Data from a Different Data File
    • Lesson 2 - Overview of How State Works in React
    • Lesson 3 - RandomQuote App
    • Lesson 4 - Lifting State Up - React Pattern Overview
    • Hands-On - Simple Counter
  • Forms and Interactivity - Grocery List App
    • Lesson 1 - Setup a Simple Form and Input
    • Lesson 2 - Build Form Profile App Using Multi-input Form Data
    • Hands-on : Build a Grocery List App
  • Connecting to the Backend - Consuming APIs - UseEffect Hook
    • Lesson 1 - Connecting to the Back End - Understanding Side Effects, Hooks and useEffect - Overview
    • Lesson 2 - Fetching Data from the Backend the Right Way with useEffect Hook
    • Lesson 3 - Setting Up Loading State
    • Hands-on :Use Dependency Array and Adding Values that Control Side Effects
  • Solo Project 1
  • RESTful APIs :Build a BookSearch App -Ver 2.0
    • Lesson 1: Build and test RESTful APIs with Postman
    • Lesson 2 - BookShelf App Structure
    • Lesson 3 - Create NavBar.jsx Component
    • Lesson 4 - Create Footer Component
    • Lesson 5 - Create BookList.jsx Component
    • Lesson 6 - Create BookCard.jsx Component
    • Lesson 7 - Creating Custom Hooks - useBooks and api-client
    • Lesson 8 - Controlling Network Activities in React with AbortController
    • Lesson 9 - Show Book Details in a Modal - Working
    • Lesson 10 - Bookshelf App Summary
  • Multi-Page Applications (MPAs)
    • Build a Multi-Page React Application
    • Multi-Page React Application
    • Hands-on Practice
  • Backend Frameworks-NEXT.JS
    • Migrating from React to Next.js
    • Lesson 1: Key Concepts of NodeJS and Express for Backend Web Development
    • Lesson 2: How to set up a new Next.js project
    • Lesson 3: How to create Layouts and Pages
    • Hands-on Practice 1
    • Hands on Practice 2
      • New Project & Folder Structure
      • File-Based Routing
      • Server vs Client Components & Router Hooks
      • Start On The Navbar
      • Navbar Links, Dropdowns & React Icons
      • Active Links & Conditional Rendering
      • Homepage Components
      • Properties Page
      • Property Card Dynamic Data
      • Home Property Listings
      • Custom Not Found & Loading Pages
  • Git and GitHubs
    • Git Installation
    • Git Commands
    • GitHub Repository
    • Hands-on Practice
  • Database in Application
    • React Supabase CRUD
    • Hands-on: Note Taking App
  • NoSQL Database
    • Installing MongoDB Community Edition
    • System Env Path Setting
    • How to use MongoDB Shell
    • How to Connect and Use Mongosh in VS Code via MongoDB Extension
    • MongoDB Guide
  • Solo Project 2
  • Deployment and Web Hosting
    • Lesson 1. React+Vite+TS+Shadcn Project
    • Lesson 2. Deploying a React Vite App to Vercel from Vercel CLI
    • Lesson 3 Connecting to GitHub Repo and Automate Deployment
  • Solo Project 3
  • Final Term Project
    • Level 1 Team Project
    • Level 1 Team Project
    • Level 1 Team Project
    • Level 1 Team Project
    • Level 2 Team Project
    • Level 2 Team Project
    • Level 3 Team Project
    • Level 3 Team Project
Powered by GitBook
On this page
  • 1. The Concept of Custom Hooks in React
  • What are Custom Hooks?
  • When to Use Custom Hooks
  • Benefits of Using Custom Hooks
  • How to Create a Custom Hook
  • Example:
  • Conclusion
  • 2. Setup the api-client File and Implementing fetchBooks
  • Step 1. Create the services Folder
  • Step 2. Implement api-client.js
  • Step 3. Implement useBooks.js
  • Step 4. Refactor AppBookShelf.jsx
  • Step 5. Benefits of This Refactor
  1. RESTful APIs :Build a BookSearch App -Ver 2.0

Lesson 7 - Creating Custom Hooks - useBooks and api-client

PreviousLesson 6 - Create BookCard.jsx ComponentNextLesson 8 - Controlling Network Activities in React with AbortController

Last updated 5 months ago

1. The Concept of Custom Hooks in React

What are Custom Hooks?

  • Reusable logic functions: Custom hooks are JavaScript functions that encapsulate reusable logic for React components. They allow you to extract common logic from multiple components and reuse it, promoting modularity and code reuse.

  • Start with "use": Custom hook functions should be named with the prefix "use" to signify that they are custom hooks.

  • Use built-in hooks: Custom hooks can use other built-in React hooks like useState, useEffect, and useContext.

When to Use Custom Hooks

Custom hooks are particularly useful when you have logic that needs to be shared across multiple components or when you want to organize your code into smaller, more manageable units. Here are some common scenarios where custom hooks can be beneficial:

  • Fetching data: You can create a custom hook to handle fetching data from an API, caching it, and managing loading states.

  • Form management: You can create a custom hook to handle form validation, input handling, and resetting form states.

  • State management: You can create custom hooks to manage local state that is specific to a component or group of components.

  • Authentication: You can create a custom hook to handle user authentication and manage user session data.

  • Caching: You can create a custom hook to cache data in memory or local storage to improve performance.

Benefits of Using Custom Hooks

  • Improved code readability and maintainability: Custom hooks help to break down complex logic into smaller, more manageable units, making your code easier to read and understand.

  • Increased reusability: Custom hooks allow you to reuse logic across multiple components, reducing code duplication and improving code efficiency.

  • Better modularity: Custom hooks promote modularity by encapsulating specific functionalities, making it easier to isolate and test individual components.

  • Enhanced readability: Custom hooks can help to improve the readability of your code by giving descriptive names to common logic patterns.

How to Create a Custom Hook

To create a custom hook, simply define a JavaScript function that starts with the "use" prefix and follows the rules for React hooks. Inside the function, you can use other built-in hooks and define the logic that you want to encapsulate. Finally, you can return any values that you want to make available to the component that uses the custom hook.

Example:

Here's a simple example of a custom hook that fetches data from an API:

JavaScript Code for Custom Hook - useFetch.js

import { useState, useEffect } from 'react';

function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    fetch(url)
      .then(response => response.json())
      .then(data => {
        setData(data);
        setLoading(false);
      })
      .catch(error => {
        setError(error);
        setLoading(false);
      });
  }, [url]);

  return { data, loading, error };
}

You can then use this custom hook in any React component that needs to fetch data from the specified URL.

Conclusion

Custom hooks are a powerful feature in React that allow you to write reusable, modular, and maintainable code. They can be used to encapsulate common logic patterns, improve code readability, and enhance the overall development experience. By leveraging custom hooks effectively, you can create more efficient and scalable React applications.

2. Setup the api-client File and Implementing fetchBooks

To implement a custom hook (useBooks.js) and refactor the AppBookShelf.jsx component for better modularity, follow these steps:

Step 1. Create the services Folder

  • Inside the src folder, create a new folder named services.


Step 2. Implement api-client.js

Create a file named api-client.js in the services folder.

Code for api-client.js

const BASE_URL = 'https://www.googleapis.com/books/v1';

export const fetchBooks = async (query) => {
  try {
    const response = await fetch(`${BASE_URL}/volumes?q=${query}`);
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    const data = await response.json();
    return data.items || [];
  } catch (error) {
    console.error('Error fetching books:', error);
    throw error; // Re-throw the error for the caller to handle
  }
};

Explanation:

  1. BASE_URL:

    • Stores the base URL for the Google Books API.

  2. fetchBooks Function:

    • Accepts a query parameter.

    • Makes an API request using fetch.

    • Returns an array of books or an empty array if none are found.

    • Logs errors and re-throws them for the caller to handle.


Step 3. Implement useBooks.js

Create a file named useBooks.js in the services folder.

Code for useBooks.js

import { useState, useEffect } from 'react';
import { fetchBooks } from './api-client';

const useBooks = (query) => {
  const [books, setBooks] = useState([]);
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    const fetchBookData = async () => {
      setLoading(true);
      setError(null);
      try {
        const bookData = await fetchBooks(query);
        setBooks(bookData);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    };

    if (query) {
      fetchBookData();
    }
  }, [query]);

  return { books, error, loading };
};

export default useBooks;

Explanation:

  1. State Variables:

    • books: Holds the fetched book data.

    • error: Stores error messages if the fetch fails.

    • loading: Indicates whether the data is currently being fetched.

  2. useEffect Hook:

    • Executes fetchBookData whenever the query changes.

  3. Return Value:

    • Exposes books, error, and loading to the parent component.


Step 4. Refactor AppBookShelf.jsx

Modify AppBookShelf.jsx to use the useBooks hook.

Updated Code for AppBookShelf.jsx

import React, { useState, useEffect } from 'react';
import NavBar from './components/NavBar';
import BookList from './components/BookList';
import Footer from './components/Footer';
import useBooks from './services/useBooks';
import 'bootstrap/dist/css/bootstrap.min.css';
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'


const AppBookShelf = () => {
  const [query, setQuery] = useState('react'); // Default query for API
  const { books, error, loading } = useBooks(query); // Use custom hook

  // Handle query updates from child components
  const handleSearch = (newQuery) => {
    setQuery(newQuery);
  };

  return (
    <div className="container mt-5">
      <NavBar query={query} onSearch={handleSearch} />

      {loading ? (
        <p className="text-center">Loading...</p>
      ) : error ? (
        <p className="text-center text-danger">Error: {error}</p>
      ) : (
        <BookListUpdates books={books} query={query} />
      )}

      <Footer />
    </div>
  );
};

export default AppBookShelf;

Explanation:

  1. Import useBooks:

    • Fetches book data using the custom hook.

  2. State Handling:

    • Displays loading, error, or book list based on the hook's output.

  3. Separation of Concerns:

    • The fetchBooks logic is moved out of the component, improving maintainability.


Step 5. Benefits of This Refactor

  1. Reusability:

    • The useBooks hook can be reused in other components or projects.

  2. Modularity:

    • api-client.js separates the API interaction from the application logic.

  3. Simplified Parent Component:

    • AppBookShelf focuses on rendering UI and handling user interaction.

This completes the implementation of a modular architecture using a custom hook and API client.