浅谈React useTransition并发特性

 更新时间:2026年05月13日 08:16:11   作者:兆子龙  
本文主要介绍了React的useTransition Hook,它可以帮助开发者将某些状态更新标记为“非紧急”,从而优化用户体验,并提供了注意事项和性能优化建议,感兴趣的可以了解一下

一、为什么需要 useTransition

在 React 中,所有状态更新默认都是紧急的,会立即阻塞 UI。

function SearchPage() {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);
  const handleChange = (e) => {
    const value = e.target.value;
    setQuery(value);  // 紧急更新
    // 耗时的过滤操作
    const filtered = hugeList.filter(item => 
      item.name.includes(value)
    );
    setResults(filtered);  // 也是紧急更新,会卡顿
  };
  return (
    <>
      <input value={query} onChange={handleChange} />
      <Results data={results} />
    </>
  );
}

问题:输入时会卡顿,因为每次输入都要等待过滤完成。

二、useTransition 的解决方案

useTransition 可以将某些更新标记为"非紧急",让 React 优先处理用户交互。

import { useState, useTransition } from 'react';

function SearchPage() {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);
  const [isPending, startTransition] = useTransition();

  const handleChange = (e) => {
    const value = e.target.value;
    setQuery(value);  // 紧急更新,立即响应
    
    startTransition(() => {
      // 非紧急更新,可以被打断
      const filtered = hugeList.filter(item => 
        item.name.includes(value)
      );
      setResults(filtered);
    });
  };

  return (
    <>
      <input value={query} onChange={handleChange} />
      {isPending && <Spinner />}
      <Results data={results} />
    </>
  );
}

效果:输入流畅,过滤操作在后台进行。

三、核心概念

返回值

const [isPending, startTransition] = useTransition();
  • isPending: 是否有待处理的 transition
  • startTransition: 将更新标记为 transition

紧急 vs 非紧急更新

// 紧急更新:立即执行,不可打断
setQuery(value);

// 非紧急更新:可以被打断,延迟执行
startTransition(() => {
  setResults(filtered);
});

四、实战场景

场景 1:搜索过滤

function ProductList() {
  const [searchTerm, setSearchTerm] = useState('');
  const [filteredProducts, setFilteredProducts] = useState(products);
  const [isPending, startTransition] = useTransition();

  const handleSearch = (value) => {
    setSearchTerm(value);
    
    startTransition(() => {
      const filtered = products.filter(p =>
        p.name.toLowerCase().includes(value.toLowerCase())
      );
      setFilteredProducts(filtered);
    });
  };

  return (
    <>
      <input
        value={searchTerm}
        onChange={e => handleSearch(e.target.value)}
        placeholder="搜索商品..."
      />
      {isPending && <div className="loading">搜索中...</div>}
      <div className="products">
        {filteredProducts.map(p => (
          <ProductCard key={p.id} {...p} />
        ))}
      </div>
    </>
  );
}

场景 2:Tab 切换

function TabContainer() {
  const [tab, setTab] = useState('home');
  const [isPending, startTransition] = useTransition();

  const handleTabChange = (newTab) => {
    startTransition(() => {
      setTab(newTab);  // 切换 tab 是非紧急的
    });
  };

  return (
    <>
      <div className="tabs">
        <button
          onClick={() => handleTabChange('home')}
          className={tab === 'home' ? 'active' : ''}
        >
          首页
        </button>
        <button
          onClick={() => handleTabChange('profile')}
          className={tab === 'profile' ? 'active' : ''}
        >
          个人中心
        </button>
      </div>
      
      {isPending && <LoadingBar />}
      
      <div className="tab-content">
        {tab === 'home' && <HomePage />}
        {tab === 'profile' && <ProfilePage />}
      </div>
    </>
  );
}

场景 3:路由切换

function App() {
  const [page, setPage] = useState('home');
  const [isPending, startTransition] = useTransition();

  const navigate = (newPage) => {
    startTransition(() => {
      setPage(newPage);
    });
  };

  return (
    <>
      <nav>
        <button onClick={() => navigate('home')}>首页</button>
        <button onClick={() => navigate('about')}>关于</button>
        <button onClick={() => navigate('contact')}>联系</button>
      </nav>
      
      {isPending && <TopLoadingBar />}
      
      <main>
        {page === 'home' && <Home />}
        {page === 'about' && <About />}
        {page === 'contact' && <Contact />}
      </main>
    </>
  );
}

五、与 useDeferredValue 对比

// useTransition:主动标记更新
const [isPending, startTransition] = useTransition();
startTransition(() => {
  setValue(newValue);
});

// useDeferredValue:被动延迟值
const deferredValue = useDeferredValue(value);
特性useTransitionuseDeferredValue
使用方式包裹更新函数包裹值
控制权主动控制被动延迟
isPending
适用场景控制更新时机延迟渲染

六、注意事项

1. 只能在 transition 中更新 state

// ✅ 正确
startTransition(() => {
  setState(newValue);
});

// ❌ 错误:不能包含异步操作
startTransition(async () => {
  const data = await fetchData();
  setState(data);
});

2. 异步操作需要特殊处理

const handleClick = async () => {
  const data = await fetchData();
  
  startTransition(() => {
    setState(data);  // 只有 setState 在 transition 中
  });
};

3. 不要过度使用

// ❌ 不需要:简单的状态更新
startTransition(() => {
  setCount(count + 1);
});

// ✅ 需要:耗时的计算或渲染
startTransition(() => {
  setResults(expensiveFilter(data));
});

七、性能优化

配合 memo 使用

const ExpensiveList = memo(({ items }) => {
  return items.map(item => <ExpensiveItem key={item.id} {...item} />);
});

function App() {
  const [query, setQuery] = useState('');
  const [items, setItems] = useState(allItems);
  const [isPending, startTransition] = useTransition();

  const handleSearch = (value) => {
    setQuery(value);
    startTransition(() => {
      setItems(allItems.filter(i => i.name.includes(value)));
    });
  };

  return (
    <>
      <input value={query} onChange={e => handleSearch(e.target.value)} />
      {isPending && <Spinner />}
      <ExpensiveList items={items} />
    </>
  );
}

八、与 Suspense 配合

function App() {
  const [tab, setTab] = useState('home');
  const [isPending, startTransition] = useTransition();

  return (
    <>
      <Tabs value={tab} onChange={(t) => {
        startTransition(() => setTab(t));
      }} />
      
      <Suspense fallback={<Skeleton />}>
        {isPending && <InlineSpinner />}
        {tab === 'home' && <Home />}
        {tab === 'posts' && <Posts />}
      </Suspense>
    </>
  );
}

到此这篇关于浅谈React useTransition并发特性的文章就介绍到这了,更多相关React useTransition并发内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 关于useEffect的第二个参数解读

    关于useEffect的第二个参数解读

    这篇文章主要介绍了关于useEffect的第二个参数,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-09-09
  • React简介入门教程

    React简介入门教程

    本文总结了React的基础知识点,包括环境搭建、核心概念(JSX、组件、props、state、事件处理、条件渲染、列表渲染)以及组件进阶(生命周期、Hooks、通信),适合零基础开发者学习,涵盖理论与实操,适合React项目的开发和维护,感兴趣的朋友跟随小编一起看看吧
    2026-02-02
  • React split实现分割字符串的使用示例

    React split实现分割字符串的使用示例

    当我们需要将一个字符串按照指定的分隔符进行分割成数组时,我们可以在组件的生命周期方法中使用split方法来实现这个功能,本文就来介绍一下,感兴趣的可以了解下
    2023-10-10
  • React Flux与Redux设计及使用原理

    React Flux与Redux设计及使用原理

    这篇文章主要介绍了React Flux与Redux设计及使用,Redux最主要是用作应用状态的管理。简言之,Redux用一个单独的常量状态树(state对象)保存这一整个应用的状态,这个对象不能直接被改变
    2023-03-03
  • react 报错Module build failed: BrowserslistError: Unknown browser query `dead`问题的解决方法

    react 报错Module build failed: Browserslis

    这篇文章主要介绍了react 报错Module build failed: BrowserslistError: Unknown browser query `dead`问题的解决方法,需要的朋友可以参考下
    2023-06-06
  • React 记忆缓存的三种方法实现

    React 记忆缓存的三种方法实现

    本文主要介绍了React 记忆缓存的三种方法实现,包含React.memo、useMemo、useCallback,用于避免不必要的组件重渲染和计算,感兴趣的可以了解一下
    2025-09-09
  • 归纳总结Remix 表单常用方法及示例详解

    归纳总结Remix 表单常用方法及示例详解

    这篇文章主要为大家归纳总结了Remix 表单常用方法及示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03
  • 从源码到架构:React useActionState 深度解析

    从源码到架构:React useActionState 深度解析

    React 19引入的 useActionState是近年来React Hooks 体系中设计最精巧的API 之一,本文给大家介绍从源码到架构:React useActionState 深度剖析,感兴趣的朋友跟随小编一起看看吧
    2026-05-05
  • react中用less的问题

    react中用less的问题

    本文主要介绍了react中用less的问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-04-04
  • 在react中使用 indexDb的方法

    在react中使用 indexDb的方法

    在React中使用IndexedDB进行前端离线存储,可以存储大量数据,支持复杂的数据类型和高性能查询,通过示例展示了如何创建数据库、添加数据、查询数据和构建一个简单的待办事项应用,感兴趣的朋友跟随小编一起看看吧
    2024-11-11

最新评论