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
- Setting Up a New React Project
- Syntax of
useCallback - Real-Time Project: Employee Management System with Search Functionality
- Project Setup
- Creating the Employee Component
- Defining the Search Function
- Using
useCallbackto Memoize the Search Function
- Conclusion
Setting Up a New React Project
First, let’s create a new React project using the create-react-app tool.
-
Open your terminal and run the following command:
npx create-react-app usecallback-employee-app -
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
incrementfunction is memoized usinguseCallbackand 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
-
Open the project directory in your code editor.
-
Remove the default content from
src/App.jsandsrc/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
-
Create a new file named
Employee.jsin thesrcdirectory. -
Define the
Employeecomponent:// 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
-
Memoize the Search Function: The
handleSearchfunction is memoized usinguseCallbackand will only be re-created if its dependencies change (in this case, there are no dependencies).const handleSearch = useCallback((event) => { setSearchTerm(event.target.value); }, []); -
Filter Employees: The
filteredEmployeesarray is created by filtering theemployeesarray based on thesearchTerm.const filteredEmployees = employees.filter((employee) => `${employee.firstName} ${employee.lastName} ${employee.email}` .toLowerCase() .includes(searchTerm.toLowerCase()) );
Managing Focus with useRef
-
Render the Search Input and Employee List: The search input and the list of employees are rendered based on the
filteredEmployeesarray.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> ); -
Create a CSS file named
Employee.cssto 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.