Full Stack Development

useTransition

by Tomas Trescak t.trescak@westernsydney.edu.au

useTransition

Introduction

  • Modern UIs must feel fast
  • Expensive updates can block interactions
  • Solution : useTransition

useTransition

Introduction

  • Typing can lag if updates are slow
  • Expensive operations (like filtering) make UI feel slow
  • đź”´ Issue : The UI freezes when executing code
    const handleSearch = (e) => {
  setQuery(e.target.value);
  
  // products can be 1000000s of records
  setFilteredProducts(
    products.filter((p) => p.includes(e.target.value))
  );
};
  

useTransaction

/

Example

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

const products = Array.from(
  { length: 5000000 }, 
  (_, i) => `Product ${i + 1}`
);

function ProductList() {
  const [query, setQuery] = useState("");
  const [filteredProducts, setFilteredProducts] = 
    useState(products);

  const handleSearch = (e) => {
    setQuery(e.target.value);
    setFilteredProducts(
      products.filter((p) => p.includes(e.target.value))
    );
  };

  return (
    <div>
      <input 
        type="text" 
        value={query} 
        onChange={handleSearch} 
        placeholder="Search..." />
      <ul>
        {filteredProducts.slice(0,20).map((product) => (
          <li key={product}>{product}</li>
        ))}
      </ul>
    </div>
  );
}

render(<ProductList />)
    

useTransaction

/

Example

      import React, { useState, render, useTransition } from "react";

const products = Array.from(
  { length: 5000000 }, 
  (_, i) => `Product ${i + 1}`
);

function ProductList() {
  const [query, setQuery] = useState("");
  const [filteredProducts, setFilteredProducts] = 
    useState(products);
  const [isPending, startTransition] = useTransition();

  const handleSearch = (e) => {
    setQuery(e.target.value);

    startTransition(() => {
      setFilteredProducts(
        products.filter((p) => p.includes(e.target.value))
      );
    });
  };

  return (
    <div>
      <input 
        type="text" 
        value={query} 
        onChange={handleSearch} 
        placeholder="Search..." />
      {isPending && <p>Loading...</p>}
      <ul>
        {filteredProducts.slice(0, 20).map((product) => (
          <li key={product}>{product}</li>
        ))}
      </ul>
    </div>
  );
}

render(<ProductList />)
    

useTransition

Usage

  • Separates urgent vs. non-urgent updates
  • Prevents UI freezing
  • Similar structure to useState
    const [isPending, startTransition] = useTransition();

const handleSearch = (e) => {
  setQuery(e.target.value); // important
  
  startTransition(() => {   // not important
    setFilteredProducts(
      products.filter((p) => p.includes(e.target.value))
    );
  });
};

return isPending ? "Loading ..." : null;
  

useTransition

usage

  • âś… Best Use Cases

    • Filtering large lists
    • Sorting heavy datasets
    • Rendering complex components
  • ❌ Avoid When

    • Updates must be immediate (e.g., form validation).
    • The expensive update is already optimized (e.g. using memoization).