React useCallback Hook

Introduction

In this chapter, we will explore the useCallback hook in React. This hook allows you to memoize functions, preventing them from being re-created on every render. This can improve performance by reducing unnecessary re-renders of child components that rely on the functions as props. We will create a new React project from scratch, explain the syntax of useCallback, and walk through a real-time project step by step to demonstrate its usage.

Table of Contents

  1. Setting Up a New React Project
  2. Syntax of useCallback
  3. Real-Time Project: Employee Management System with Search Functionality
    • Project Setup
    • Creating the Employee Component
    • Defining the Search Function
    • Using useCallback to Memoize the Search Function
  4. Conclusion

Setting Up a New React Project

First, let’s create a new React project using the create-react-app tool.

  1. Open your terminal and run the following command:

    npx create-react-app usecallback-employee-app
    
  2. Navigate to the project directory:

    cd usecallback-employee-app
    

Syntax of useCallback

The useCallback hook returns a memoized callback function that only changes if one of the dependencies has changed. This is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders.

Syntax

const memoizedCallback = useCallback(() => {
  // Function logic
}, [dependencies]);
  • memoizedCallback: The memoized version of the callback function.
  • dependencies: An array of dependencies that, when changed, will cause the callback function to be re-created.

Example

import React, { useState, useCallback } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  const increment = useCallback(() => {
    setCount((prevCount) => prevCount + 1);
  }, []);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
}

export default Counter;

Explanation:

  • The increment function is memoized using useCallback and will only be re-created if its dependencies change (in this case, there are no dependencies).

Real-Time Project: Employee Management System with Search Functionality

Project Setup

  1. Open the project directory in your code editor.

  2. Remove the default content from src/App.js and src/App.css:

    // src/App.js
    import React from 'react';
    import './App.css';
    import Employee from './Employee';
    
    function App() {
      return (
        <div className="App">
          <h1>Employee Management System</h1>
          <Employee />
        </div>
      );
    }
    
    export default App;
    
    /* src/App.css */
    .App {
      text-align: center;
      padding: 20px;
    }
    
    h1 {
      margin-bottom: 20px;
    }
    

Creating the Employee Component

  1. Create a new file named Employee.js in the src directory.

  2. Define the Employee component:

    // src/Employee.js
    import React, { useState, useCallback } from 'react';
    import './Employee.css';
    
    const initialEmployees = [
      { id: 1, firstName: 'John', lastName: 'Doe', email: 'john@example.com' },
      { id: 2, firstName: 'Jane', lastName: 'Smith', email: 'jane@example.com' },
      { id: 3, firstName: 'Sara', lastName: 'Williams', email: 'sara@example.com' },
    ];
    
    function Employee() {
      const [employees, setEmployees] = useState(initialEmployees);
      const [searchTerm, setSearchTerm] = useState('');
    
      const handleSearch = useCallback((event) => {
        setSearchTerm(event.target.value);
      }, []);
    
      const filteredEmployees = employees.filter((employee) =>
        `${employee.firstName} ${employee.lastName} ${employee.email}`
          .toLowerCase()
          .includes(searchTerm.toLowerCase())
      );
    
      return (
        <div className="container mt-5">
          <input
            type="text"
            className="form-control mb-3"
            placeholder="Search employees..."
            value={searchTerm}
            onChange={handleSearch}
          />
          <ul className="list-group">
            {filteredEmployees.map((employee) => (
              <li key={employee.id} className="list-group-item">
                {employee.id} - {employee.firstName} {employee.lastName} ({employee.email})
              </li>
            ))}
          </ul>
        </div>
      );
    }
    
    export default Employee;
    

Using useCallback to Memoize the Search Function

  1. Memoize the Search Function: The handleSearch function is memoized using useCallback and will only be re-created if its dependencies change (in this case, there are no dependencies).

    const handleSearch = useCallback((event) => {
      setSearchTerm(event.target.value);
    }, []);
    
  2. Filter Employees: The filteredEmployees array is created by filtering the employees array based on the searchTerm.

    const filteredEmployees = employees.filter((employee) =>
      `${employee.firstName} ${employee.lastName} ${employee.email}`
        .toLowerCase()
        .includes(searchTerm.toLowerCase())
    );
    

Managing Focus with useRef

  1. Render the Search Input and Employee List: The search input and the list of employees are rendered based on the filteredEmployees array.

    return (
      <div className="container mt-5">
        <input
          type="text"
          className="form-control mb-3"
          placeholder="Search employees..."
          value={searchTerm}
          onChange={handleSearch}
        />
        <ul className="list-group">
          {filteredEmployees.map((employee) => (
            <li key={employee.id} className="list-group-item">
              {employee.id} - {employee.firstName} {employee.lastName} ({employee.email})
            </li>
          ))}
        </ul>
      </div>
    );
    
  2. Create a CSS file named Employee.css to style the Employee component:

    /* src/Employee.css */
    .container {
      max-width: 600px;
      margin: 0 auto;
      text-align: left;
    }
    
    .form-control {
      width: 100%;
      padding: 10px;
      margin: 5px 0;
      box-sizing: border-box;
      border: 1px solid #ccc;
      border-radius: 4px;
    }
    
    .list-group-item {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 10px;
      border: 1px solid #ccc;
      border-radius: 4px;
      margin-bottom: 10px;
    }
    

Conclusion

In this chapter, we created a new React project and explored the useCallback hook. We learned the syntax of useCallback and walked through a real-time project step by step to create an Employee Management System application with search functionality. By understanding and using the useCallback hook, you can memoize functions to prevent unnecessary re-renders, making your React applications more performant and efficient.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top