react-concurrent
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseReact 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: Usewith technology:mcp__documentation__fetch_docs, topic:reactfor comprehensive documentation.concurrent
完整参考:如需了解包括基于优先级的更新、结合过渡的乐观更新、路由集成、表单操作和调试技巧在内的高级并发模式,请查看advanced.md。
深度知识:使用工具,指定technology:mcp__documentation__fetch_docs,topic:react以获取全面文档。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 :
isPendingtsx
import { startTransition } from 'react';
function handleClick() {
startTransition(() => {
setPage('/heavy-page');
});
}适用于组件外部或不需要的场景:
isPendingtsx
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
| Feature | useTransition | useDeferredValue |
|---|---|---|
| Purpose | Wrap state updates | Defer a value |
| Usage | When you control the update | When you receive a value |
| Returns | | Deferred value |
| Use case | Button clicks, form submits | Props from parent |
| 特性 | useTransition | useDeferredValue |
|---|---|---|
| 用途 | 包裹状态更新 | 延迟某个值 |
| 使用场景 | 你控制更新操作时 | 你接收某个值时 |
| 返回值 | | 延迟后的值 |
| 适用案例 | 按钮点击、表单提交 | 来自父组件的Props |
Anti-Patterns
反模式
| Anti-Pattern | Why It's Bad | Correct Approach |
|---|---|---|
| Wrapping every state update | Adds unnecessary complexity | Only for heavy updates |
| Not memoizing child components | No benefit from deferred value | Use |
| Using for fast operations | Performance overhead | Reserve for slow renders (> 50ms) |
| Ignoring isPending state | User sees no feedback | Show loading indicator |
| Multiple transitions unnecessarily | Confusing behavior | Batch related updates |
| 反模式 | 弊端 | 正确做法 |
|---|---|---|
| 包裹所有状态更新 | 增加不必要的复杂度 | 仅用于大量渲染的更新 |
| 不对子组件进行记忆化 | 无法从延迟值中获益 | 使用 |
| 用于快速操作 | 带来性能开销 | 仅用于慢渲染操作(>50ms) |
| 忽略isPending状态 | 用户无反馈 | 显示加载指示器 |
| 不必要的多次过渡 | 行为混乱 | 批量处理相关更新 |
Quick Troubleshooting
快速故障排查
| Issue | Likely Cause | Solution |
|---|---|---|
| No performance improvement | Child not memoized | Add |
| Still blocking UI | Synchronous heavy computation | Move to Web Worker |
| isPending always false | Update completes too fast | No transition needed |
| Stale UI shown too long | No loading indicator | Check and display isPending |
| Transition not working | Using in React < 18 | Upgrade to React 18+ |
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 无性能提升 | 子组件未被记忆化 | 为组件添加 |
| UI仍被阻塞 | 同步大量计算 | 迁移至Web Worker |
| isPending始终为false | 更新完成过快 | 无需使用过渡 |
| 过时UI显示过久 | 无加载指示器 | 检查并显示isPending状态 |
| 过渡不生效 | 使用React <18版本 | 升级至React 18+ |
Best Practices
最佳实践
- ✅ Use for user-initiated heavy updates
- ✅ Combine with for list components
memo() - ✅ Show visual feedback during pending state
- ✅ Use for route transitions
- ✅ Prefer for received props
useDeferredValue - ❌ 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: Usewith technology:mcp__documentation__fetch_docs, topic:reactfor comprehensive documentation.concurrent
深度知识:使用工具,指定technology:mcp__documentation__fetch_docs,topic:react以获取全面文档。concurrent