useCallback
by Tomas Trescak· Advanced React

Root Folder
Not Attempted
NameProgress
Introduction
Not Read
🍰 Player
Not Read
Setup
Not Attempted
NameProgress
Software Installation
Not Read
Project Setup
Not Read
Running and Testing
Not Read
React and ReactDOM
Not Read
💡 Assignment 1: Welcome Message
Not Attempted
Submissions
Not Read
React
Not Attempted
NameProgress
JSX and Components
Not Read
Props
Not Read
👾 Exercise: Props
Not Attempted
CSS Styles
Not Read
useState and Hooks
Not Read
👾 Exercise: useState
Not Attempted
Conditional Rendering
Not Read
Lists
Not Read
👾 Exercise: Lists
Not Attempted
Forms and Events
Not Read
👾 Exercise: Forms
Not Attempted
💡 Assignment 2: Front End
Not Attempted
Pure Components - memo
Lifecycle - useEffect
Expensive? - useMemo
DOM Interactions - useRef
forwardRef
useImperativeHandle
👾 useImperativeHandle
Not Attempted
Context
useCallback
useId
useReducer
Infrastructure
Not Attempted
NameProgress
Database
Not Read
NextAuth and Github Authentication
Not Read
Prisma and ORM
Not Read
Project Setup
Not Read
Project Authentication
Not Read
APIs
Not Attempted
NameProgress
APIs
Not Read
APIs - Slides
Not Attempted
Rest APIs
Not Read
Rest APIs - Express.js
Not Read
ReastAPIs - Next.js
Not Read
Securing APIs
Not Read
Securing APIs - NextAuth
Not Read
tRPC
Not Attempted
NameProgress
tRPC
Not Read
tRPC - Routers
Not Read
tRPC - Server Rendering
Not Read
tRPC - Client Rendering
Not Read
Persisting Data
Not Read
Assignment 3: APIs
Not Read
0 / 300 XP

Lecture Transcript
If you prefer text to video, check out the transcript of the presentation above

The useCallback hook in React is used to memoize functions so that they are not recreated on every render. This helps in optimising performance, especially in scenarios where the function is passed as a prop to child components or used in expensive computations.

Every time a component re-renders, all its functions are recreated, even if their logic hasn’t changed. This can lead to unnecessary re-renders of child components or performance issues in complex apps. By memoizing a function with useCallback, you ensure the function retains its identity unless its dependencies change.

useCallback returns the same function instance as long as the dependencies don’t change. When dependencies change, a new function is created.

Here’s an example of how useCallback can prevent unnecessary re-renders.

Parent re-renders on the Increment button click.

Every time the Parent re-renders (when count changes), the handleClick function is recreated.

Even though Child is a pure component, this causes the Child component to re-render unnecessarily, as the onClick handler is a new function, albeit doing the same functionality as its previous version.

Therefore we need to make sure that this callback is not recreated unnecessarily.

For this, we apply the useCallback hook and memoise the handleClick function.

When we click the button, the Child component doesn’t re-render unless handleClick changes, which happens only if its dependencies change (none in this case).

When a function depends on state or props, you can include them in the dependency array.

The handleClick function is recreated only when the count changes, ensuring it always logs the latest value of the count.

Clicking on the Increment button re-renders child

But logging displays the correct value. Try removing the count from the dependency variables and guess what happens!

useCallback can help optimise your app. Use it when passing Functions as Props to prevent unnecessary re-renders of memoized child components.

Also, to optimise frequently used handlers like onClick, onChange, etc.

Or to memoize expensive functions that are called repeatedly in the render cycle.

But useCallback comes with small performance overhead and it also makes your code harder to read. Therefore, do not overuse this hook, and don’t wrap every function in useCallback. Use it only when there’s a clear performance benefit.

Remember that in small apps, function recreation is rarely a performance bottleneck.

To summarise ...

The purpose of useCallback is to memoize functions to prevent unnecessary re-creations and improve performance.

The syntax of use callback is defined by the callback function and a list of dependencies defining when to re-create this callback

The key use case is to prevent child re-renders, optimize event handlers, and memoise expensive functions.

But, use it judiciously; overuse can complicate code without significant benefits..

Description
All the extra information about this section

Understanding useCallback in React

The useCallback hook in React is used to memoize functions so that they are not recreated on every render. This helps in optimizing performance, especially in scenarios where the function is passed as a prop to child components or used in expensive computations.


Why useCallback?

Every time a component re-renders, all its functions are recreated, even if their logic hasn’t changed. This can lead to:

  1. Unnecessary re-renders of child components.
  2. Performance issues in complex apps.

By memoizing a function with useCallback, you ensure the function retains its identity unless its dependencies change.


How useCallback Works

const memoizedCallback = useCallback(() => {
  // Your function logic here
}, [dependencies]);
  • useCallback returns the same function instance as long as the dependencies don’t change.
  • When dependencies change, a new function is created.

Key Use Cases

  1. Preventing unnecessary renders of child components.
  2. Optimizing event handlers in large or complex components.

Basic Example

Here’s an example of how useCallback can prevent unnecessary re-renders:

Without <strong>useCallback</strong>:

import React, { useState } from "react";

const Child = React.memo(({ onClick }) => {
  console.log("Child rendered");
  return <button onClick={onClick}>Click Me</button>;
});

const Parent = () => {
  const [count, setCount] = useState(0);

  const handleClick = () => {
    console.log("Button clicked");
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <Child onClick={handleClick} />
    </div>
  );
};

export default Parent;

Behavior:

  • Every time the Parent re-renders (when count changes), the handleClick function is recreated.
  • This causes the Child component to re-render unnecessarily, even though its props haven’t changed.

With <strong>useCallback</strong>:

jsx

Copy code

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

const Child = React.memo(({ onClick }) => {
  console.log("Child rendered");
  return <button onClick={onClick}>Click Me</button>;
});

const Parent = () => {
  const [count, setCount] = useState(0);

  const handleClick = useCallback(() => {
    console.log("Button clicked");
  }, []); // No dependencies, so the function is memoized and won't change

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <Child onClick={handleClick} />
    </div>
  );
};

export default Parent;

Behavior:

  • The handleClick function is memoized using useCallback.
  • The Child component doesn’t re-render unless handleClick changes, which happens only if its dependencies change (none in this case).

Advanced Example: With Dependencies

When a function depends on state or props, you can include them in the dependency array.

const Parent = () => {
  const [count, setCount] = useState(0);

  const handleClick = useCallback(() => {
    console.log(`Count: ${count}`);
  }, [count]); // Recreate the function only if `count` changes

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <button onClick={handleClick}>Log Count</button>
    </div>
  );
};

Behavior:

  • The handleClick function is recreated only when count changes, ensuring it always logs the latest value of count.

When to Use useCallback

  1. Passing Functions as Props:
    • Prevent unnecessary re-renders of memoized child components.
  2. Event Handlers:
    • Optimize frequently used handlers like onClick, onChange, etc.
  3. Expensive Functionality:
    • Memoize expensive functions that are called repeatedly in the render cycle.

When Not to Use useCallback

  • Overuse: Don’t wrap every function in useCallback. Use it only when there’s a clear performance benefit.
  • Simple Apps: In small apps, function recreation is rarely a performance bottleneck.

Summary

  • Purpose: Memoize functions to prevent unnecessary re-creations and improve performance.
  • Syntax: useCallback(() => {...}, [dependencies])
  • Key Use Cases: Prevent child re-renders, optimize event handlers, memoize expensive functions.
  • Caution: Use it judiciously; overuse can complicate code without significant benefits.

Let me know if you’d like a deeper dive or more examples! 🚀

Maggie

Discuss with Maggie
Use the power of generative AI to interact with course content

Discussion

0 comments
Loading editor ...
Remember to be polite and report any undesirable behaviour

Category

Empty

Labels

Discussion has no labels

1 participant

user avatar

Priority

Notifications

You're not receiving notifications from this thread.
Course Outline