Skip to Content
Lab 2

Custom Hooks Implementation

Scenario

In modern React development, abstracting reusable logic into custom Hooks is a fundamental practice for building maintainable and scalable applications. You’ve been tasked with developing two common custom Hooks: usePagination for managing client-side pagination logic, and useDebounce for debouncing rapidly changing values, often used with search inputs.

This lab will challenge you to think about hook design, state management within hooks, handling dependencies, and ensuring your hooks are generic enough for reuse.


Learning Objectives

Upon successful completion of this lab, you will be able to:

  • Design and implement reusable custom React Hooks from scratch.
  • Encapsulate complex logic and state management within a custom Hook.
  • Effectively manage dependencies and side effects within custom Hooks.
  • Understand how to return values and functions from custom Hooks for use in components.
  • Apply custom Hooks to solve common problems like pagination and debouncing input.
  • Consider basic performance aspects (e.g., memoization) where applicable within custom Hooks.

Project Requirements

You will create two custom Hooks in this lab. Each hook should be implemented in its own file (e.g., usePagination.ts or usePagination.js, useDebounce.ts or useDebounce.js).

You should also create an example components directory to demonstrate the usage of your custom hooks.

usePagination Hook

Objective: Create a hook to manage pagination logic for a list of items.

Functionality:

  • Inputs:
    • totalItems: The total number of items to be paginated.
    • itemsPerPage: The number of items to display per page (default to 10).
    • initialPage: The page to start on (default to 1).
  • Return Values (Object):
    • currentPage: The current active page number.
    • totalPages: The total number of pages calculated based on totalItems and itemsPerPage.
    • startIndex: The starting index of items for the current page (0-based).
    • endIndex: The ending index of items for the current page (0-based).
    • itemsOnCurrentPage: The actual number of items on the current page (useful for the last page).
    • setPage(pageNumber): A function to jump to a specific page number.
    • nextPage(): A function to go to the next page.
    • prevPage(): A function to go to the previous page.
    • canNextPage: Boolean indicating if there is a next page.
    • canPrevPage: Boolean indicating if there is a previous page.

Implementation Details:

  • Calculate totalPages correctly (e.g., using Math.ceil).
  • Ensure currentPage does not go below 1 or above totalPages.
  • startIndex and endIndex should be calculated based on the currentPage and itemsPerPage.
  • itemsOnCurrentPage should correctly reflect the count for the last page if it’s not full.

Example Usage Component (PaginationDemo.tsx):

  • Create a component that uses your usePagination hook.
  • Simulate a list of items (e.g., an array of 100 numbers or strings).
  • Display the current page number, total pages, and the slice of items for the current page.
  • Include buttons for “Previous”, “Next”, and jumping to specific page numbers (if you wish to demonstrate setPage more thoroughly).
  • Disable Previous/Next buttons when canPrevPage or canNextPage is false.

Example Solution

Pagination Demo

Total Items: 123
  • Item 1
  • Item 2
  • Item 3
  • Item 4
  • Item 5
  • Item 6
  • Item 7
  • Item 8
  • Item 9
  • Item 10
Page of 13
Showing items 1 - 10 (Total on this page: 10)

useDebounce Hook

Objective: Create a hook to debounce a rapidly changing value.

Functionality:

  • Inputs:
    • value: The value to debounce (e.g., a search string from an input field).
    • delay: The debounce delay in milliseconds (default to 500ms).
  • Return Value:
    • debouncedValue: The value after the debounce delay has passed without value changing.

Implementation Details:

  • Use useState to store the debouncedValue.
  • Use useEffect to set up a timer (setTimeout) whenever the input value or delay changes.
  • The effect should clear the timer (using clearTimeout) if value or delay changes before the timer fires (this is the core of debouncing).
  • When the timer finally fires, update the debouncedValue state.

Example Usage Component (DebounceSearchDemo.tsx):

  • Create a component with an input field.
  • As the user types into the input, use the useDebounce hook to get the debounced version of the input’s value.
  • Display both the current input value and the debounced value.
  • You can simulate an API call or filtering action whenever the debouncedValue changes by logging to the console (e.g., “Searching for: [debouncedValue]”).

Example Solution

Debounce Search Demo

Current Input:
Debounced Value (after 500ms):

Simulated Search Results:

Type to see results.


Implementation Guidelines

  • Hook Design: Strive for clarity and reusability in your hook’s API.
  • State Management: Use useState appropriately within your hooks.
  • Side Effects: Use useEffect for any side effects. Ensure correct dependency arrays and cleanup functions.
  • TypeScript (Optional but Recommended): If you are comfortable with TypeScript, try to type your hook inputs and return values for better self-documentation and safety.
Note

Focus on the internal logic and API design of your custom Hooks. The visual styling of the demo components is secondary to the correct functionality of the hooks themselves.

💡
Tip

Test your hooks thoroughly. Consider edge cases. For usePagination, what happens if totalItems is 0? For useDebounce, how does it behave if the delay changes?


Submission

Submit your project on Canvas via a GitHub link that includes all necessary files for this lab. Ensure your custom hooks and the demo components are included and functional.


Grading Rubric

Your submission will be evaluated based on the following criteria.

CriteriaExcellentGoodFairNeeds Improvement
usePagination Hook Implementation
Correctly implements all specified functionality, manages state, and handles edge cases.
15-13 pts
• All return values correctly implemented and accurate.
• Handles edge cases (e.g., 0 totalItems, invalid page numbers) gracefully.
• Logic is clear, efficient, and well-organized.
12-10 pts
• Most return values correctly implemented.
• Handles common cases well.
• Minor issues in logic or edge case handling.
9-7 pts
• Basic pagination logic is present.
• Several functionalities may be missing or incorrect.
• Significant issues in logic.
6-0 pts
• Hook is largely non-functional or missing.
• Core requirements not met.
useDebounce Hook Implementation
Correctly implements debouncing logic using useEffect with proper cleanup.
15-13 pts
• Debouncing works perfectly, updating only after delay.
useEffect has correct dependencies and cleanup (clearTimeout).
• Handles changes in value or delay robustly.
12-10 pts
• Debouncing generally works.
useEffect dependencies and cleanup are mostly correct.
• Minor issues with rapid changes or delay updates.
9-7 pts
• Basic attempt at debouncing.
useEffect might be missing cleanup or have incorrect dependencies.
• Debouncing is unreliable.
6-0 pts
• Hook is largely non-functional or missing.
• Core debouncing logic is incorrect.
Demo Component Showcase
PaginationDemo and DebounceSearchDemo effectively demonstrate the created hooks.
10-9 pts
• Both demo components clearly showcase all features of their respective hooks.
• UI is functional and allows for easy testing of hook behavior.
• Code is clean and easy to understand.
8-7 pts
• Both demo components showcase most features of the hooks.
• UI is functional.
• Minor clarity issues in demo code.
6-5 pts
• One or both demo components are incomplete or do not clearly showcase hook functionality.
• UI may be difficult to use for testing.
4-0 pts
• Demo components are missing or non-functional.
• Hooks are not demonstrated effectively.

Total Points Possible: 40