React Tutorial - React Callback Hooks

We offer private, customized training for 3 or more people at your site or online.

To follow along with this React tutorial, you can visit GitHub to download the code we will use. We have some setup instructions on the readme file for the repository for you to code along with this lesson.

In this tutorial, you will learn how to optimize the re-rendering of a component using the Callback Hook. We will start it up by typing 'npm start' in the App.js file. This will launch the application in your default web browser and you will see a simple application that allows us to add, edit, and delete cars. You will notice when we click the edit button, it will go to "edit" mode and if you click the cancel button, it will go back to "read only" mode.

Read Only Mode

Edit Mode

In CarForm.js, you will see we have a CarForm component. Here is where we are going to put a console log.

We will see 'rendering car form' each time this CarForm component function is called.

Now if we open our developer tools to the Console and click edit, it renders the car form again. Now, nothing changed in the car form, but it rendered the parent component app. This not only renders the app itself as well as the table, but renders any other components under it, including CarForm.

What can we do to improve the performance to only render CarForm when something is changing and being passed into CarForm? We could use the memo function.

I will go to line 4 and type 'memo' and then we can wrap everything in our memo function. The memo function will only surrender when we change the incoming props. It is a shallow comparison, but if you pass the same primitive values that are the same object references, it will only re-render when changed values are passed in.

If we reload now, you will see it still rendered it again. But why did it render when we are not changing this button text at all? Our button text is hard coded to addCar. The culprit here is the appendCar function on submit. Each time we called this app function, it produced a brand new appendCar function, which is a new object reference.

CarForm.js
Here is the code as shown in CarForm.js:

import React, { useState, memo } from 'react';
import PropTypes from 'prop-types';

export const CarForm = memo(({
  buttonText, onSubmitCar,
}) => {

  console.log('rendering car form');

  const [ carForm, setCarForm ] = useState({
    make: '',
    model: '',
    year: 1900,
    color: '',
    price: 0,
  });

Then that new object reference being passed is causing the memo function to think something has changed so it re-renders the component.

That is where the callback hook comes in. We can type useCallback (line 1) to remember the previous callback function so it will use the previous callback function instead of always producing a new one. We will wrap a callback around this function and this array (line 19) is going to represent dependencies with which we might be working. So, for example, the dependency here is the array of cars, which is what it's actually complaining about here. So instead, we could type 'cars' and save that.

App.js
Here is the code as shown in App.js:

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

import { carsPropType } from './propTypes';
import { ToolHeader, CarTable, CarForm } from './components';

export const App = ({
cars: initialCars,
}) => {

const [ cars, setCars ] = useState(initialCars.concat());
const [ editCarId, setEditCarId ] = useState(-1);

const appendCar = useCallback(car => {
  setCars(cars.concat({
      ...car,
  id: Math.max(...cars.map(c => c.id), 0) + 1,
}));

setEditCarId(-1);
}, [ cars ]);

const replaceCar = car => {
  const carIndex = cars.findIndex(c => c.id === car.id);
  const newCars = cars.concat();
  newCars[carIndex] = car;
  setCars(newCars);
  setEditCarId(-1);
};

const deleteCar = carId => {
  setCars(cars.filter(c => c.id !== carId));
  setEditCarId(-1);
};

const cancelCar = () => {
  setEditCarId(-1);
};

Now watch what happens in the form. If we click Edit, you will see it did not rerender CarForm. If we click, cancel, it does not render CarForm. Now if we add a car, you will see the CarForm changes. Then if I click "Add Car" at the bottom, you will see it rendered it again. But it is only going to render CarForm if you are typing into it or if the actual underlying array of cars has changed.

In this short tutorial, you saw how to optimize the re-rendering of a component using Callback Hooks and the Memo function. As you can see, Callback Hooks and the Memo function make it easy to improve the performance of React components without having to use classes.

Accelebrate offers live, private React/Redux training for teams of 3 or more.  For more information, please see our list of React courses.

The original React Callback Hooks 5-minute video for this tutorial was recorded by Eric Greene

Eric is a professional software developer specializing in HTML, CSS, and JavaScript technologies. He has been developing software and delivering training classes for nearly 19 years. He holds the MCSD Certification for ASP.NET Web Applications and is a Microsoft Certified Trainer.

Learn faster

Our live, instructor-led lectures are far more effective than pre-recorded classes

Satisfaction guarantee

If your team is not 100% satisfied with your training, we do what's necessary to make it right

Learn online from anywhere

Whether you are at home or in the office, we make learning interactive and engaging

Multiple Payment Options

We accept check, ACH/EFT, major credit cards, and most purchase orders



Recent Training Locations

Alabama

Birmingham

Huntsville

Montgomery

Alaska

Anchorage

Arizona

Phoenix

Tucson

Arkansas

Fayetteville

Little Rock

California

Los Angeles

Oakland

Orange County

Sacramento

San Diego

San Francisco

San Jose

Colorado

Boulder

Colorado Springs

Denver

Connecticut

Hartford

DC

Washington

Florida

Fort Lauderdale

Jacksonville

Miami

Orlando

Tampa

Georgia

Atlanta

Augusta

Savannah

Hawaii

Honolulu

Idaho

Boise

Illinois

Chicago

Indiana

Indianapolis

Iowa

Cedar Rapids

Des Moines

Kansas

Wichita

Kentucky

Lexington

Louisville

Louisiana

New Orleans

Maine

Portland

Maryland

Annapolis

Baltimore

Frederick

Hagerstown

Massachusetts

Boston

Cambridge

Springfield

Michigan

Ann Arbor

Detroit

Grand Rapids

Minnesota

Minneapolis

Saint Paul

Mississippi

Jackson

Missouri

Kansas City

St. Louis

Nebraska

Lincoln

Omaha

Nevada

Las Vegas

Reno

New Jersey

Princeton

New Mexico

Albuquerque

New York

Albany

Buffalo

New York City

White Plains

North Carolina

Charlotte

Durham

Raleigh

Ohio

Akron

Canton

Cincinnati

Cleveland

Columbus

Dayton

Oklahoma

Oklahoma City

Tulsa

Oregon

Portland

Pennsylvania

Philadelphia

Pittsburgh

Rhode Island

Providence

South Carolina

Charleston

Columbia

Greenville

Tennessee

Knoxville

Memphis

Nashville

Texas

Austin

Dallas

El Paso

Houston

San Antonio

Utah

Salt Lake City

Virginia

Alexandria

Arlington

Norfolk

Richmond

Washington

Seattle

Tacoma

West Virginia

Charleston

Wisconsin

Madison

Milwaukee

Alberta

Calgary

Edmonton

British Columbia

Vancouver

Manitoba

Winnipeg

Nova Scotia

Halifax

Ontario

Ottawa

Toronto

Quebec

Montreal

Puerto Rico

San Juan