React Advanced

0% completed

Previous
Next
Concurrency with useTransition

In this lesson, you'll learn everything about the useTransition hook and how you can implement it in your React apps. By the end of this lesson, you'll have learned about the important role concurrency with this hook plays in building apps with a good user experience.

What is the useTransition Hook?

useTransition is a React Hook designed to help manage concurrency by allowing you to mark certain state updates as non-urgent. This is useful in cases where an application needs to handle both urgent and non-urgent updates simultaneously without affecting UI responsiveness.

In traditional React rendering, all state updates are processed synchronously, meaning that heavy operations (such as filtering large lists) can cause UI lag. With useTransition, React can prioritize urgent updates (like user interactions) while deferring non-urgent updates, ensuring a smoother user experience.

Understanding useTransition and Its Role in Concurrency

The useTransition hook works by:

  1. Marking certain updates as non-urgent. React will then process them when it has available rendering time.
  2. Allowing urgent updates to proceed first. User interactions like typing, clicking, or selecting items remain smooth.
  3. Providing a pending state. With this, you can show loading indicators while non-urgent updates are being processed.

Syntax and Basic Usage

The useTransition Hook returns two values:

  • startTransition(callback) – A function that wraps non-urgent state updates.
  • isPending – A boolean that indicates whether a transition is still in progress.

Here’s the basic syntax:

const [isPending, startTransition] = useTransition();

To use it, wrap non-urgent updates inside startTransition:

startTransition(() => { // Non-urgent state update });

Example

Lets look at an example that uses the useTransition hook to prevent UI lag in search filtering.

Consider an application where a user types into a search box to filter a large list of items. Without useTransition, filtering would be synchronous, causing UI lag when processing large datasets.

Without useTransition (Causing UI Lag)

import { useState } from "react"; const ItemList = ({ items }) => { const [query, setQuery] = useState(""); const [filteredItems, setFilteredItems] = useState(items); const handleSearch = (e) => { setQuery(e.target.value); // Immediately updating state setFilteredItems(items.filter(item => item.includes(e.target.value))); }; return ( <div> <input type="text" value={query} onChange={handleSearch} placeholder="Search..." /> <ul> {filteredItems.map(item => <li key={item}>{item}</li>)} </ul> </div> ); };

In this code, there is a problem. And the problem is; as the user types, the filtering process happens immediately, causing noticeable UI lag, especially for large lists.

With useTransition (Smoother UI)

To solve this problem, we use the useTransition hook:

import { useState, useTransition } from "react"; const ItemList = ({ items }) => { const [query, setQuery] = useState(""); const [filteredItems, setFilteredItems] = useState(items); const [isPending, startTransition] = useTransition(); // Using useTransition const handleSearch = (e) => { setQuery(e.target.value); startTransition(() => { // Marking filtering as a non-urgent update setFilteredItems(items.filter(item => item.includes(e.target.value))); }); }; return ( <div> <input type="text" value={query} onChange={handleSearch} placeholder="Search..." /> {isPending && <p>Updating list...</p>} {/* Show loading indicator during transition */} <ul> {filteredItems.map(item => <li key={item}>{item}</li>)} </ul> </div> ); };

Here, we've made a significant improvement. Now, React prioritizes user input (query state update) while deferring the filtering process, preventing UI lag and ensuring a smooth typing experience.

Benefits of useTransition in Concurrency

1. Improves User Experience by Prioritizing Urgent Updates: React ensures that interactions like typing remain smooth, preventing UI lag caused by expensive computations or large data operations.

2. Reduces UI Freezing in Expensive Computations: Since non-urgent updates are deferred, React prevents slow state updates from blocking UI interactions.

3. Provides a Pending State to Improve Perceived Performance: With the isPending flag, you can show feedback (e.g., a loading indicator) while the transition is still in progress, enhancing perceived performance.

Drawbacks and Considerations of useTransition

There are some things you need to factor in before or while using this hook, such as:

1. Not Suitable for Every Update

  • useTransition is designed for state updates that do not require an immediate UI response.
  • Urgent updates (e.g., button clicks, controlled input fields) should not be wrapped in startTransition.

2. Can Cause Inconsistent UI if Used Incorrectly

  • If used improperly, some UI components might display outdated data for longer than expected.
  • Developers should be cautious when deferring updates that depend on immediate user interactions.

3. Requires React 18 or Later

  • useTransition is available starting from React 18. Applications using older versions must upgrade to utilize concurrency features.

Best Practices for Using useTransition

1. Use for Non-Urgent Updates Only

  • Suitable for search filtering, list rendering, animations, or API responses.
  • Not ideal for immediate interactions like form inputs or button clicks.

2. Always Handle the Pending State (isPending)

  • Show a loading indicator when updates are in progress to avoid confusion.
  • Example: Display "Updating list..." when filtering a large dataset.

3. Avoid Wrapping Every Update in startTransition

  • Only use useTransition where necessary to prevent unnecessary delays.

.....

.....

.....

Like the course? Get enrolled and start learning!
Previous
Next