react-concurrent

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

React Concurrent Features

React并发特性

Full Reference: See advanced.md for advanced concurrent patterns including priority-based updates, optimistic updates with transitions, router integration, form actions, and debugging techniques.
Deep Knowledge: Use
mcp__documentation__fetch_docs
with technology:
react
, topic:
concurrent
for comprehensive documentation.
完整参考:如需了解包括基于优先级的更新、结合过渡的乐观更新、路由集成、表单操作和调试技巧在内的高级并发模式,请查看advanced.md
深度知识:使用
mcp__documentation__fetch_docs
工具,指定technology:
react
,topic:
concurrent
以获取全面文档。

When NOT to Use This Skill

何时不使用此技能

Skip this skill when:
  • Using React 17 or earlier (not available)
  • Building simple apps with fast renders
  • All state updates are already fast (< 16ms)
  • Working with non-React frameworks
  • Server Components handle the work (Next.js App Router)
在以下情况跳过本技能:
  • 使用React 17或更早版本(无此特性)
  • 构建渲染速度快的简单应用
  • 所有状态更新已足够快(<16ms)
  • 使用非React框架
  • 由Server Components处理相关工作(Next.js App Router)

Overview

概述

Concurrent React allows interrupting renders to keep the UI responsive:
Traditional Rendering:
[Update starts]────────────────────────[Render complete]
                    UI blocked!

Concurrent Rendering:
[Update starts]──[pause]──[higher priority]──[resume]──[complete]
                    UI remains responsive!
Concurrent React允许中断渲染过程以保持UI响应性:
传统渲染:
[更新开始]────────────────────────[渲染完成]
                    UI被阻塞!

并发渲染:
[更新开始]──[暂停]──[更高优先级任务]──[恢复]──[完成]
                    UI保持响应!

useTransition

useTransition

Mark state updates as non-urgent (can be interrupted):
tsx
import { useState, useTransition } from 'react';

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

  function selectTab(nextTab: string) {
    startTransition(() => {
      setTab(nextTab);
    });
  }

  return (
    <div>
      <nav>
        {['home', 'about', 'contact'].map((t) => (
          <button key={t} onClick={() => selectTab(t)}>
            {t}
          </button>
        ))}
      </nav>

      <div className={isPending ? 'opacity-50' : ''}>
        {tab === 'home' && <Home />}
        {tab === 'about' && <About />}
        {tab === 'contact' && <Contact />}
      </div>
    </div>
  );
}
将状态标记为非紧急更新(可被中断):
tsx
import { useState, useTransition } from 'react';

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

  function selectTab(nextTab: string) {
    startTransition(() => {
      setTab(nextTab);
    });
  }

  return (
    <div>
      <nav>
        {['home', 'about', 'contact'].map((t) => (
          <button key={t} onClick={() => selectTab(t)}>
            {t}
          </button>
        ))}
      </nav>

      <div className={isPending ? 'opacity-50' : ''}>
        {tab === 'home' && <Home />}
        {tab === 'about' && <About />}
        {tab === 'contact' && <Contact />}
      </div>
    </div>
  );
}

useDeferredValue

useDeferredValue

Defer updating a value to keep UI responsive:
tsx
import { useState, useDeferredValue, memo } from 'react';

function SearchPage() {
  const [query, setQuery] = useState('');
  const deferredQuery = useDeferredValue(query);
  const isStale = query !== deferredQuery;

  return (
    <div>
      <input
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        placeholder="Search..."
      />

      <div className={isStale ? 'opacity-50' : ''}>
        <SearchResults query={deferredQuery} />
      </div>
    </div>
  );
}

// Memoize to actually benefit from deferred value
const SearchResults = memo(function SearchResults({ query }: { query: string }) {
  const results = useMemo(() => {
    return items.filter(item =>
      item.name.toLowerCase().includes(query.toLowerCase())
    );
  }, [query]);

  return <ul>{results.map(item => <li key={item.id}>{item.name}</li>)}</ul>;
});
延迟更新某个值以保持UI响应性:
tsx
import { useState, useDeferredValue, memo } from 'react';

function SearchPage() {
  const [query, setQuery] = useState('');
  const deferredQuery = useDeferredValue(query);
  const isStale = query !== deferredQuery;

  return (
    <div>
      <input
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        placeholder="Search..."
      />

      <div className={isStale ? 'opacity-50' : ''}>
        <SearchResults query={deferredQuery} />
      </div>
    </div>
  );
}

// 进行记忆化处理以真正从延迟值中获益
const SearchResults = memo(function SearchResults({ query }: { query: string }) {
  const results = useMemo(() => {
    return items.filter(item =>
      item.name.toLowerCase().includes(query.toLowerCase())
    );
  }, [query]);

  return <ul>{results.map(item => <li key={item.id}>{item.name}</li>)}</ul>;
});

startTransition (without Hook)

startTransition(无需Hook)

For use outside components or when you don't need
isPending
:
tsx
import { startTransition } from 'react';

function handleClick() {
  startTransition(() => {
    setPage('/heavy-page');
  });
}
适用于组件外部或不需要
isPending
的场景:
tsx
import { startTransition } from 'react';

function handleClick() {
  startTransition(() => {
    setPage('/heavy-page');
  });
}

Suspense with Transitions

Suspense与过渡结合使用

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

  return (
    <div>
      <nav>
        <button onClick={() => startTransition(() => setTab('posts'))}>
          Posts
        </button>
      </nav>

      <Suspense fallback={<TabSkeleton />}>
        <div className={isPending ? 'opacity-50' : ''}>
          {tab === 'posts' && <Posts />}
        </div>
      </Suspense>
    </div>
  );
}
tsx
function App() {
  const [tab, setTab] = useState('home');
  const [isPending, startTransition] = useTransition();

  return (
    <div>
      <nav>
        <button onClick={() => startTransition(() => setTab('posts'))}>
          Posts
        </button>
      </nav>

      <Suspense fallback={<TabSkeleton />}>
        <div className={isPending ? 'opacity-50' : ''}>
          {tab === 'posts' && <Posts />}
        </div>
      </Suspense>
    </div>
  );
}

useTransition vs useDeferredValue

useTransition vs useDeferredValue

FeatureuseTransitionuseDeferredValue
PurposeWrap state updatesDefer a value
UsageWhen you control the updateWhen you receive a value
Returns
[isPending, startTransition]
Deferred value
Use caseButton clicks, form submitsProps from parent
特性useTransitionuseDeferredValue
用途包裹状态更新延迟某个值
使用场景你控制更新操作时你接收某个值时
返回值
[isPending, startTransition]
延迟后的值
适用案例按钮点击、表单提交来自父组件的Props

Anti-Patterns

反模式

Anti-PatternWhy It's BadCorrect Approach
Wrapping every state updateAdds unnecessary complexityOnly for heavy updates
Not memoizing child componentsNo benefit from deferred valueUse
memo()
Using for fast operationsPerformance overheadReserve for slow renders (> 50ms)
Ignoring isPending stateUser sees no feedbackShow loading indicator
Multiple transitions unnecessarilyConfusing behaviorBatch related updates
反模式弊端正确做法
包裹所有状态更新增加不必要的复杂度仅用于大量渲染的更新
不对子组件进行记忆化无法从延迟值中获益使用
memo()
用于快速操作带来性能开销仅用于慢渲染操作(>50ms)
忽略isPending状态用户无反馈显示加载指示器
不必要的多次过渡行为混乱批量处理相关更新

Quick Troubleshooting

快速故障排查

IssueLikely CauseSolution
No performance improvementChild not memoizedAdd
memo()
to component
Still blocking UISynchronous heavy computationMove to Web Worker
isPending always falseUpdate completes too fastNo transition needed
Stale UI shown too longNo loading indicatorCheck and display isPending
Transition not workingUsing in React < 18Upgrade to React 18+
问题可能原因解决方案
无性能提升子组件未被记忆化为组件添加
memo()
UI仍被阻塞同步大量计算迁移至Web Worker
isPending始终为false更新完成过快无需使用过渡
过时UI显示过久无加载指示器检查并显示isPending状态
过渡不生效使用React <18版本升级至React 18+

Best Practices

最佳实践

  • ✅ Use for user-initiated heavy updates
  • ✅ Combine with
    memo()
    for list components
  • ✅ Show visual feedback during pending state
  • ✅ Use for route transitions
  • ✅ Prefer
    useDeferredValue
    for received props
  • ❌ Don't wrap every state update
  • ❌ Don't use for fast operations
  • ❌ Don't forget to memoize child components
  • ✅ 用于用户触发的大量渲染更新
  • ✅ 结合
    memo()
    用于列表组件
  • ✅ 在等待状态期间显示视觉反馈
  • ✅ 用于路由过渡
  • ✅ 对于接收的Props优先使用
    useDeferredValue
  • ❌ 不要包裹所有状态更新
  • ❌ 不要用于快速操作
  • ❌ 不要忘记对子组件进行记忆化

Reference Documentation

参考文档

Deep Knowledge: Use
mcp__documentation__fetch_docs
with technology:
react
, topic:
concurrent
for comprehensive documentation.
深度知识:使用
mcp__documentation__fetch_docs
工具,指定technology:
react
,topic:
concurrent
以获取全面文档。