- Spec files
npm-react
Describes: pkg:npm/react@18.3.x
- Description
- React is a JavaScript library for building user interfaces with declarative, component-based architecture.
- Author
- tessl
- Last updated
concurrent.md docs/
1# Concurrent Features23React's concurrent features enable better user experience by allowing React to interrupt and prioritize updates. These features help maintain responsive UIs even during heavy computations.45## Capabilities67### startTransition89Marks state updates as non-urgent transitions that can be interrupted by more urgent updates.1011```javascript { .api }12/**13* Marks state updates as non-urgent transitions14* @param scope - Function containing non-urgent state updates15*/16function startTransition(scope: () => void): void;17```1819**Usage Examples:**2021```javascript22import React, { startTransition, useState } from 'react';2324// Search with urgent input updates and non-urgent results25function SearchComponent() {26const [query, setQuery] = useState('');27const [results, setResults] = useState([]);28const [isSearching, setIsSearching] = useState(false);2930const handlesearch = (newQuery) => {31// Urgent update - keeps input responsive32setQuery(newQuery);3334// Non-urgent update - can be interrupted35startTransition(() => {36setIsSearching(true);3738// Simulate expensive search operation39const searchResults = performExpensiveSearch(newQuery);40setResults(searchResults);41setIsSearching(false);42});43};4445return (46<div>47<input48value={query}49onChange={(e) => handleSearch(e.target.value)}50placeholder="Search..."51/>5253{isSearching && <div>Searching...</div>}5455<SearchResults results={results} />56</div>57);58}5960// Tab switching with smooth transitions61function TabContainer() {62const [activeTab, setActiveTab] = useState(0);63const [tabContent, setTabContent] = useState(null);6465const switchTab = (tabIndex) => {66// Urgent update - immediately switch active tab67setActiveTab(tabIndex);6869// Non-urgent update - load and render content70startTransition(() => {71const content = loadTabContent(tabIndex);72setTabContent(content);73});74};7576return (77<div>78<div className="tab-nav">79{tabs.map((tab, index) => (80<button81key={index}82className={index === activeTab ? 'active' : ''}83onClick={() => switchTab(index)}84>85{tab.title}86</button>87))}88</div>8990<div className="tab-content">91{tabContent || <div>Loading tab content...</div>}92</div>93</div>94);95}9697// Data filtering with responsive UI98function DataTable({ data }) {99const [filter, setFilter] = useState('');100const [filteredData, setFilteredData] = useState(data);101const [sortOrder, setSortOrder] = useState('asc');102103const handleFilterChange = (newFilter) => {104// Urgent update - keep filter input responsive105setFilter(newFilter);106107// Non-urgent update - filter and sort data108startTransition(() => {109const filtered = data.filter(item =>110item.name.toLowerCase().includes(newFilter.toLowerCase())111);112113const sorted = sortData(filtered, sortOrder);114setFilteredData(sorted);115});116};117118const handleSort = (order) => {119setSortOrder(order);120121startTransition(() => {122const sorted = sortData(filteredData, order);123setFilteredData(sorted);124});125};126127return (128<div>129<div className="controls">130<input131value={filter}132onChange={(e) => handleFilterChange(e.target.value)}133placeholder="Filter data..."134/>135136<select value={sortOrder} onChange={(e) => handleSort(e.target.value)}>137<option value="asc">Sort A-Z</option>138<option value="desc">Sort Z-A</option>139</select>140</div>141142<table>143<tbody>144{filteredData.map(item => (145<tr key={item.id}>146<td>{item.name}</td>147<td>{item.value}</td>148</tr>149))}150</tbody>151</table>152</div>153);154}155```156157### useTransition (Hook Version)158159Hook version of startTransition that also provides pending state.160161```javascript { .api }162/**163* Hook for managing transitions with pending state164* @returns Tuple with isPending boolean and startTransition function165*/166function useTransition(): [boolean, (callback: () => void) => void];167```168169**Usage Examples:**170171```javascript172import React, { useTransition, useState } from 'react';173174// Search with loading indicator175function SearchWithStatus() {176const [query, setQuery] = useState('');177const [results, setResults] = useState([]);178const [isPending, startTransition] = useTransition();179180const handleSearch = (newQuery) => {181setQuery(newQuery);182183startTransition(() => {184// This will set isPending to true until updates complete185const searchResults = performExpensiveSearch(newQuery);186setResults(searchResults);187});188};189190return (191<div>192<input193value={query}194onChange={(e) => handleSearch(e.target.value)}195placeholder="Search..."196/>197198{isPending && (199<div className="search-pending">200<Spinner /> Searching...201</div>202)}203204<SearchResults results={results} />205</div>206);207}208209// Form with async validation210function AsyncForm() {211const [formData, setFormData] = useState({ email: '', username: '' });212const [errors, setErrors] = useState({});213const [isPending, startTransition] = useTransition();214215const validateField = (field, value) => {216setFormData(prev => ({ ...prev, [field]: value }));217218startTransition(() => {219// Async validation (API call)220validateFieldAsync(field, value).then(validationResult => {221setErrors(prev => ({222...prev,223[field]: validationResult.error224}));225});226});227};228229return (230<form className={isPending ? 'validating' : ''}>231<div>232<input233type="email"234value={formData.email}235onChange={(e) => validateField('email', e.target.value)}236placeholder="Email"237/>238{errors.email && <span className="error">{errors.email}</span>}239</div>240241<div>242<input243type="text"244value={formData.username}245onChange={(e) => validateField('username', e.target.value)}246placeholder="Username"247/>248{errors.username && <span className="error">{errors.username}</span>}249</div>250251{isPending && <div className="validation-indicator">Validating...</div>}252253<button type="submit" disabled={isPending || Object.keys(errors).length > 0}>254Submit255</button>256</form>257);258}259260// Paginated data with smooth transitions261function PaginatedList({ data, itemsPerPage = 10 }) {262const [currentPage, setCurrentPage] = useState(1);263const [displayData, setDisplayData] = useState([]);264const [isPending, startTransition] = useTransition();265266const changePage = (page) => {267// Immediate update for active page indicator268setCurrentPage(page);269270// Transition for data loading/processing271startTransition(() => {272const startIndex = (page - 1) * itemsPerPage;273const endIndex = startIndex + itemsPerPage;274const pageData = data.slice(startIndex, endIndex);275276// Simulate processing time for large datasets277setDisplayData(processDataForDisplay(pageData));278});279};280281const totalPages = Math.ceil(data.length / itemsPerPage);282283return (284<div>285<div className={`data-container ${isPending ? 'loading' : ''}`}>286{isPending && <div className="loading-overlay">Loading...</div>}287<DataList items={displayData} />288</div>289290<Pagination291currentPage={currentPage}292totalPages={totalPages}293onPageChange={changePage}294disabled={isPending}295/>296</div>297);298}299```300301### useDeferredValue302303Defers updating a value until more urgent updates have completed.304305```javascript { .api }306/**307* Defers value updates for performance optimization308* @param value - Value to defer309* @returns Deferred version of the value310*/311function useDeferredValue<T>(value: T): T;312```313314**Usage Examples:**315316```javascript317import React, { useDeferredValue, useState, useMemo } from 'react';318319// Expensive list filtering320function ProductList({ products }) {321const [filter, setFilter] = useState('');322const deferredFilter = useDeferredValue(filter);323324// Expensive filtering operation uses deferred value325const filteredProducts = useMemo(() => {326if (!deferredFilter) return products;327328return products.filter(product =>329product.name.toLowerCase().includes(deferredFilter.toLowerCase()) ||330product.description.toLowerCase().includes(deferredFilter.toLowerCase()) ||331product.tags.some(tag => tag.toLowerCase().includes(deferredFilter.toLowerCase()))332);333}, [products, deferredFilter]);334335return (336<div>337<input338value={filter} // Input stays responsive with immediate value339onChange={(e) => setFilter(e.target.value)}340placeholder="Filter products..."341/>342343<div className="product-grid">344{filteredProducts.map(product => (345<ProductCard key={product.id} product={product} />346))}347</div>348</div>349);350}351352// Chart with deferred data updates353function DataVisualization({ dataset, chartType }) {354const [zoomLevel, setZoomLevel] = useState(1);355const [selectedRange, setSelectedRange] = useState(null);356357// Defer expensive data processing358const deferredZoom = useDeferredValue(zoomLevel);359const deferredRange = useDeferredValue(selectedRange);360361const processedData = useMemo(() => {362// Expensive data processing for visualization363return processDataForChart(dataset, {364zoom: deferredZoom,365range: deferredRange,366type: chartType367});368}, [dataset, deferredZoom, deferredRange, chartType]);369370return (371<div>372<div className="chart-controls">373<input374type="range"375min="0.5"376max="5"377step="0.1"378value={zoomLevel}379onChange={(e) => setZoomLevel(parseFloat(e.target.value))}380/>381<span>Zoom: {zoomLevel}x</span>382</div>383384<Chart data={processedData} onRangeSelect={setSelectedRange} />385</div>386);387}388389// Search results with deferred query390function SmartSearch() {391const [query, setQuery] = useState('');392const [category, setCategory] = useState('all');393const deferredQuery = useDeferredValue(query);394395const searchResults = useMemo(() => {396if (!deferredQuery.trim()) return [];397398// Expensive search across multiple data sources399return performComprehensiveSearch(deferredQuery, category);400}, [deferredQuery, category]);401402const isStale = query !== deferredQuery;403404return (405<div>406<div className="search-controls">407<input408value={query}409onChange={(e) => setQuery(e.target.value)}410placeholder="Search..."411/>412413<select414value={category}415onChange={(e) => setCategory(e.target.value)}416>417<option value="all">All Categories</option>418<option value="products">Products</option>419<option value="articles">Articles</option>420<option value="users">Users</option>421</select>422</div>423424<div className={`search-results ${isStale ? 'stale' : ''}`}>425{isStale && (426<div className="search-updating">Updating results...</div>427)}428429<SearchResults results={searchResults} />430</div>431</div>432);433}434435// Complex form with deferred validation436function ComplexForm() {437const [formData, setFormData] = useState({438name: '',439email: '',440preferences: []441});442443// Defer expensive validation444const deferredFormData = useDeferredValue(formData);445446const validationResults = useMemo(() => {447return validateComplexForm(deferredFormData);448}, [deferredFormData]);449450const isValidating = formData !== deferredFormData;451452const updateField = (field, value) => {453setFormData(prev => ({ ...prev, [field]: value }));454};455456return (457<form className={isValidating ? 'validating' : ''}>458<input459value={formData.name}460onChange={(e) => updateField('name', e.target.value)}461placeholder="Full Name"462/>463464<input465value={formData.email}466onChange={(e) => updateField('email', e.target.value)}467placeholder="Email"468type="email"469/>470471<PreferenceSelector472value={formData.preferences}473onChange={(prefs) => updateField('preferences', prefs)}474/>475476{isValidating && <div className="validation-pending">Validating...</div>}477478<ValidationSummary results={validationResults} />479480<button481type="submit"482disabled={isValidating || !validationResults.isValid}483>484Submit485</button>486</form>487);488}489```490491## Types492493```javascript { .api }494// Concurrent feature types495function startTransition(scope: () => void): void;496497function useTransition(): [boolean, (callback: () => void) => void];498499function useDeferredValue<T>(value: T): T;500501// Transition callback type502type TransitionCallback = () => void;503504// Hook return types505type UseTransitionReturn = [boolean, (callback: TransitionCallback) => void];506```