Facebook Pixel

Using startTransition

In this tutorial, you will learn how to use startTransition to keep your UI responsive during heavy updates. startTransition lets React prioritize user interactions over expensive renders without you manually managing performance hacks.


What We Will Learn

  • What startTransition is and why it exists
  • The difference between urgent and non urgent updates
  • How React schedules work during transitions
  • Real world examples where startTransition matters
  • Common mistakes and best practices

By the end, you will know exactly when and why to use transitions.


The Problem startTransition Solves

Sometimes an update is:

  • Computationally expensive
  • Causes many components to re-render
  • Blocks typing, clicking, or scrolling

Example problems users notice:

  • Typing feels laggy
  • Buttons freeze briefly
  • Search results lock the UI

The issue is not correctness. The issue is priority.


Urgent vs Non Urgent Updates

React 19 treats updates in two categories:

Urgent Updates

  • Typing in an input
  • Clicking buttons
  • Hover interactions
  • Focus changes

These must feel instant.


Non Urgent Updates

  • Filtering large lists
  • Sorting data
  • Rendering charts
  • Navigating between views

These can wait a little without harming UX.


What startTransition Does

startTransition tells React:

This update is important, but do it when the browser is free.

React then:

  • Keeps the UI responsive
  • Interrupts rendering if the user interacts
  • Finishes the transition when possible

Nothing blocks the main thread unnecessarily.


Basic Example Without startTransition

// components/search.tsx
"use client"
 
import { useState } from "react"
 
export function Search({ items }: { items: string[] }) {
  const [query, setQuery] = useState("")
 
  const results = items.filter(item =>
    item.toLowerCase().includes(query.toLowerCase())
  )
 
  return (
    <>
      <input
        value={query}
        onChange={e => setQuery(e.target.value)}
      />
 
      <ul>
        {results.map(item => (
          <li key={item}>{item}</li>
        ))}
      </ul>
    </>
  )
}

Typing updates query and filters immediately. If items is large, typing becomes sluggish.


Adding startTransition

// components/search.tsx
"use client"
 
import { useState, startTransition } from "react"
 
export function Search({ items }: { items: string[] }) {
  const [query, setQuery] = useState("")
  const [filtered, setFiltered] = useState(items)
 
  function onChange(value: string) {
    setQuery(value)
 
    startTransition(() => {
      setFiltered(
        items.filter(item =>
          item.toLowerCase().includes(value.toLowerCase())
        )
      )
    })
  }
 
  return (
    <>
      <input
        value={query}
        onChange={e => onChange(e.target.value)}
      />
 
      <ul>
        {filtered.map(item => (
          <li key={item}>{item}</li>
        ))}
      </ul>
    </>
  )
}

Now:

  • Typing stays instant
  • Filtering happens in the background
  • React pauses work if the user keeps typing

What Changed Conceptually

Before:

  • One update
  • Everything blocks until done

After:

  • Urgent update first
  • Heavy work scheduled later
  • UI remains interactive

You did not optimize the algorithm. You optimized priority.


Transitions Are Not Async

This is important.

startTransition does not:

  • Make code async
  • Delay execution with timers
  • Run on another thread

It only tells React how to schedule the update.


Showing Pending State with useTransition

Sometimes you want to show feedback.

import { useTransition } from "react"
 
const [isPending, startTransition] = useTransition()

Example:

<button disabled={isPending}>
  {isPending ? "Updating..." : "Update"}
</button>

This helps users understand that work is happening.


Common Use Cases

Use startTransition for:

  • Search filtering
  • Sorting tables
  • Pagination
  • Switching tabs with heavy content
  • Rendering large lists

Avoid it for:

  • Controlled inputs
  • Form validation
  • Immediate UI feedback

Common Mistakes

Wrapping Everything in a Transition

Do not do this:

startTransition(() => {
  setInput(value)
})

Typing must always be urgent.


Using Transitions as a Performance Fix

If your code is slow because of bad algorithms, fix that first.

startTransition is about user experience, not brute force optimization.


How This Fits with the React Compiler

The React Compiler optimizes re-renders. startTransition optimizes when rendering happens.

They solve different problems and work best together.


Mental Model

Think of startTransition like a priority lane:

  • User interactions go in the fast lane
  • Heavy rendering goes in the slow lane
  • React switches lanes automatically

This keeps the app feeling smooth.


Conclusion

startTransition is a powerful but focused tool in React 19.

It helps you:

  • Keep UIs responsive
  • Prioritize user interactions
  • Handle heavy updates gracefully