DEV Community

Mohamed Idris
Mohamed Idris

Posted on

The useTransition react hook

The useTransition hook in React 18 is designed to help optimize the user experience by treating certain tasks as less urgent, allowing the app to stay responsive even during heavy computations. Here’s how it works and how it can be applied:

Problem:

Imagine you have a scenario where a user input triggers some heavy computation—like filtering or generating a large list based on the input. For instance, typing into an input might trigger the app to process thousands of items. While this happens, the UI becomes unresponsive and feels frozen, which is frustrating for the user.

Solution: Using useTransition

With React 18, we can use the useTransition hook to mark certain tasks as less urgent. This allows React to keep the UI responsive (like updating the input field) while performing heavy computations (like generating 5000 items) in the background.

Before useTransition:

In this example, each keystroke in the input field triggers the creation of 5,000 items, which blocks the UI, making it unresponsive.

import { useState } from 'react';

const App = () => {
  const [text, setText] = useState('');
  const [items, setItems] = useState([]);

  const handleChange = (e) => {
    setText(e.target.value);

    // Simulate slow computation
    const newItems = Array.from({ length: 5000 }, (_, index) => {
      return (
        <div key={index}>
          <img
            src="https://images.unsplash.com/photo-1767131636996-ae27286d36fb?q=80&w=870&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
            alt=""
            width={50}
            height={50}
            style={{ borderRadius: '50%' }}
          />
        </div>
      );
    });
    setItems(newItems);
  };

  return (
    <section>
      <form className="form">
        <input
          type="text"
          className="form-input"
          value={text}
          onChange={handleChange}
        />
      </form>
      <h4>Items Below</h4>

      <div
        style={{
          display: 'grid',
          gridTemplateColumns: '1fr 1fr 1fr',
          marginTop: '2rem',
        }}
      >
        {items}
      </div>
    </section>
  );
};
export default App;
Enter fullscreen mode Exit fullscreen mode

In this setup, each time the user types, the entire computation of 5000 items is triggered, making the app slow to respond to user input.

After Using useTransition:

To fix this, we can wrap the slow computation in a startTransition function. This way, React will prioritize the user input (which needs to be fast) and perform the computation (generating the items) in the background without blocking the UI.

import { useState, useTransition } from 'react';

const App = () => {
  const [text, setText] = useState('');
  const [items, setItems] = useState([]);
  const [isPending, startTransition] = useTransition();  // useTransition hook

  const handleChange = (e) => {
    setText(e.target.value);

    // Slow down computation wrapped in startTransition
    startTransition(() => {
      const newItems = Array.from({ length: 5000 }, (_, index) => {
        return (
          <div key={index}>
            <img
              src="https://images.unsplash.com/photo-1767131636996-ae27286d36fb?q=80&w=870&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
              alt=""
              width={50}
              height={50}
              style={{ borderRadius: '50%' }}
            />
          </div>
        );
      });
      setItems(newItems);  // Set the items state
    });
  };

  return (
    <section>
      <form className="form">
        <input
          type="text"
          className="form-input"
          value={text}
          onChange={handleChange}
        />
      </form>
      <h4>Items Below</h4>

      {isPending ? (  // Check if the transition is still pending
        <div>Loading...</div>
      ) : (
        <div
          style={{
            display: 'grid',
            gridTemplateColumns: '1fr 1fr 1fr',
            marginTop: '2rem',
          }}
        >
          {items}  {/* Display the generated items */}
        </div>
      )}
    </section>
  );
};
export default App;
Enter fullscreen mode Exit fullscreen mode

Explanation of Changes:

  • useTransition: This hook returns two things: isPending and startTransition.

    • isPending: A boolean indicating if the transition (the slow operation) is still in progress.
    • startTransition: A function that wraps the slow function (like generating 5,000 items). This marks the operation as low priority and allows React to prioritize the UI updates.
  • startTransition(() => { ... }): The slow function, which in this case is the computation that generates the 5,000 items, is wrapped inside startTransition.

  • isPending: The component conditionally renders a "Loading..." message while the computation is still ongoing, and displays the items once the computation is complete.

Result:

  • Input Responsiveness: The input field remains fast and responsive, even while the heavy computation (generating 5,000 items) is happening in the background.
  • Non-blocking UI: The UI is no longer blocked during heavy computations, providing a smoother user experience.

Conclusion:

The useTransition hook is a powerful tool for handling expensive operations in React 18. By marking non-urgent tasks (like filtering or generating large lists) as low priority, we can keep the UI responsive, improving the overall user experience.

Credits: John Smilga's course

Top comments (2)

Collapse
 
edriso profile image
Mohamed Idris

Simulating Slow Computation with CPU Throttling

To simulate a slow computation and see the impact on performance, you can slow down the CPU from the browser's performance tab. Here's how:

  1. Open Chrome DevTools (Right-click → Inspect → go to the "Performance" tab).
  2. In the Performance tab, click the three vertical dots (more options) on the top-right.
  3. Select "More tools""Performance insights".
  4. In the "Performance insights" panel, under Throttling, choose "CPU" and adjust the slider to slow down the CPU (e.g., make it 4x slower).

This will simulate a slower CPU, helping you see how the app performs when computations are delayed. You'll notice that without optimizations like useTransition, the app can become sluggish, but with useTransition, the UI remains responsive while background tasks are processed.

Collapse
 
edriso profile image
Mohamed Idris