淺談React useTransition并發(fā)特性
一、為什么需要 useTransition
在 React 中,所有狀態(tài)更新默認(rèn)都是緊急的,會(huì)立即阻塞 UI。
function SearchPage() {
const [query, setQuery] = useState('');
const [results, setResults] = useState([]);
const handleChange = (e) => {
const value = e.target.value;
setQuery(value); // 緊急更新
// 耗時(shí)的過(guò)濾操作
const filtered = hugeList.filter(item =>
item.name.includes(value)
);
setResults(filtered); // 也是緊急更新,會(huì)卡頓
};
return (
<>
<input value={query} onChange={handleChange} />
<Results data={results} />
</>
);
}問(wèn)題:輸入時(shí)會(huì)卡頓,因?yàn)槊看屋斎攵家却^(guò)濾完成。
二、useTransition 的解決方案
useTransition 可以將某些更新標(biāo)記為"非緊急",讓 React 優(yōu)先處理用戶(hù)交互。
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); // 緊急更新,立即響應(yīng)
startTransition(() => {
// 非緊急更新,可以被打斷
const filtered = hugeList.filter(item =>
item.name.includes(value)
);
setResults(filtered);
});
};
return (
<>
<input value={query} onChange={handleChange} />
{isPending && <Spinner />}
<Results data={results} />
</>
);
}
效果:輸入流暢,過(guò)濾操作在后臺(tái)進(jìn)行。
三、核心概念
返回值
const [isPending, startTransition] = useTransition();
isPending: 是否有待處理的 transitionstartTransition: 將更新標(biāo)記為 transition
緊急 vs 非緊急更新
// 緊急更新:立即執(zhí)行,不可打斷
setQuery(value);
// 非緊急更新:可以被打斷,延遲執(zhí)行
startTransition(() => {
setResults(filtered);
});
四、實(shí)戰(zhàn)場(chǎng)景
場(chǎng)景 1:搜索過(guò)濾
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>
</>
);
}
場(chǎng)景 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' : ''}
>
首頁(yè)
</button>
<button
onClick={() => handleTabChange('profile')}
className={tab === 'profile' ? 'active' : ''}
>
個(gè)人中心
</button>
</div>
{isPending && <LoadingBar />}
<div className="tab-content">
{tab === 'home' && <HomePage />}
{tab === 'profile' && <ProfilePage />}
</div>
</>
);
}
場(chǎng)景 3:路由切換
function App() {
const [page, setPage] = useState('home');
const [isPending, startTransition] = useTransition();
const navigate = (newPage) => {
startTransition(() => {
setPage(newPage);
});
};
return (
<>
<nav>
<button onClick={() => navigate('home')}>首頁(yè)</button>
<button onClick={() => navigate('about')}>關(guān)于</button>
<button onClick={() => navigate('contact')}>聯(lián)系</button>
</nav>
{isPending && <TopLoadingBar />}
<main>
{page === 'home' && <Home />}
{page === 'about' && <About />}
{page === 'contact' && <Contact />}
</main>
</>
);
}
五、與 useDeferredValue 對(duì)比
// useTransition:主動(dòng)標(biāo)記更新
const [isPending, startTransition] = useTransition();
startTransition(() => {
setValue(newValue);
});
// useDeferredValue:被動(dòng)延遲值
const deferredValue = useDeferredValue(value);
| 特性 | useTransition | useDeferredValue |
|---|---|---|
| 使用方式 | 包裹更新函數(shù) | 包裹值 |
| 控制權(quán) | 主動(dòng)控制 | 被動(dòng)延遲 |
| isPending | 有 | 無(wú) |
| 適用場(chǎng)景 | 控制更新時(shí)機(jī) | 延遲渲染 |
六、注意事項(xiàng)
1. 只能在 transition 中更新 state
// ? 正確
startTransition(() => {
setState(newValue);
});
// ? 錯(cuò)誤:不能包含異步操作
startTransition(async () => {
const data = await fetchData();
setState(data);
});
2. 異步操作需要特殊處理
const handleClick = async () => {
const data = await fetchData();
startTransition(() => {
setState(data); // 只有 setState 在 transition 中
});
};
3. 不要過(guò)度使用
// ? 不需要:簡(jiǎn)單的狀態(tài)更新
startTransition(() => {
setCount(count + 1);
});
// ? 需要:耗時(shí)的計(jì)算或渲染
startTransition(() => {
setResults(expensiveFilter(data));
});
七、性能優(yōu)化
配合 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>
</>
);
}
到此這篇關(guān)于淺談React useTransition并發(fā)特性的文章就介紹到這了,更多相關(guān)React useTransition并發(fā)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于useEffect的第二個(gè)參數(shù)解讀
這篇文章主要介紹了關(guān)于useEffect的第二個(gè)參數(shù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09
React?split實(shí)現(xiàn)分割字符串的使用示例
當(dāng)我們需要將一個(gè)字符串按照指定的分隔符進(jìn)行分割成數(shù)組時(shí),我們可以在組件的生命周期方法中使用split方法來(lái)實(shí)現(xiàn)這個(gè)功能,本文就來(lái)介紹一下,感興趣的可以了解下2023-10-10
React?Flux與Redux設(shè)計(jì)及使用原理
這篇文章主要介紹了React?Flux與Redux設(shè)計(jì)及使用,Redux最主要是用作應(yīng)用狀態(tài)的管理。簡(jiǎn)言之,Redux用一個(gè)單獨(dú)的常量狀態(tài)樹(shù)(state對(duì)象)保存這一整個(gè)應(yīng)用的狀態(tài),這個(gè)對(duì)象不能直接被改變2023-03-03
react 報(bào)錯(cuò)Module build failed: Browserslis
這篇文章主要介紹了react 報(bào)錯(cuò)Module build failed: BrowserslistError: Unknown browser query `dead`問(wèn)題的解決方法,需要的朋友可以參考下2023-06-06
從源碼到架構(gòu):React?useActionState?深度解析
React 19引入的 useActionState是近年來(lái)React Hooks 體系中設(shè)計(jì)最精巧的API 之一,本文給大家介紹從源碼到架構(gòu):React?useActionState?深度剖析,感興趣的朋友跟隨小編一起看看吧2026-05-05

