npm-react

Description
React is a JavaScript library for building user interfaces with declarative, component-based architecture.
Author
tessl
Last updated

How to use

npx @tessl/cli registry install tessl/npm-react@18.3.0

concurrent.md docs/

1
# Concurrent Features
2
3
React'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.
4
5
## Capabilities
6
7
### startTransition
8
9
Marks state updates as non-urgent transitions that can be interrupted by more urgent updates.
10
11
```javascript { .api }
12
/**
13
* Marks state updates as non-urgent transitions
14
* @param scope - Function containing non-urgent state updates
15
*/
16
function startTransition(scope: () => void): void;
17
```
18
19
**Usage Examples:**
20
21
```javascript
22
import React, { startTransition, useState } from 'react';
23
24
// Search with urgent input updates and non-urgent results
25
function SearchComponent() {
26
const [query, setQuery] = useState('');
27
const [results, setResults] = useState([]);
28
const [isSearching, setIsSearching] = useState(false);
29
30
const handlesearch = (newQuery) => {
31
// Urgent update - keeps input responsive
32
setQuery(newQuery);
33
34
// Non-urgent update - can be interrupted
35
startTransition(() => {
36
setIsSearching(true);
37
38
// Simulate expensive search operation
39
const searchResults = performExpensiveSearch(newQuery);
40
setResults(searchResults);
41
setIsSearching(false);
42
});
43
};
44
45
return (
46
<div>
47
<input
48
value={query}
49
onChange={(e) => handleSearch(e.target.value)}
50
placeholder="Search..."
51
/>
52
53
{isSearching && <div>Searching...</div>}
54
55
<SearchResults results={results} />
56
</div>
57
);
58
}
59
60
// Tab switching with smooth transitions
61
function TabContainer() {
62
const [activeTab, setActiveTab] = useState(0);
63
const [tabContent, setTabContent] = useState(null);
64
65
const switchTab = (tabIndex) => {
66
// Urgent update - immediately switch active tab
67
setActiveTab(tabIndex);
68
69
// Non-urgent update - load and render content
70
startTransition(() => {
71
const content = loadTabContent(tabIndex);
72
setTabContent(content);
73
});
74
};
75
76
return (
77
<div>
78
<div className="tab-nav">
79
{tabs.map((tab, index) => (
80
<button
81
key={index}
82
className={index === activeTab ? 'active' : ''}
83
onClick={() => switchTab(index)}
84
>
85
{tab.title}
86
</button>
87
))}
88
</div>
89
90
<div className="tab-content">
91
{tabContent || <div>Loading tab content...</div>}
92
</div>
93
</div>
94
);
95
}
96
97
// Data filtering with responsive UI
98
function DataTable({ data }) {
99
const [filter, setFilter] = useState('');
100
const [filteredData, setFilteredData] = useState(data);
101
const [sortOrder, setSortOrder] = useState('asc');
102
103
const handleFilterChange = (newFilter) => {
104
// Urgent update - keep filter input responsive
105
setFilter(newFilter);
106
107
// Non-urgent update - filter and sort data
108
startTransition(() => {
109
const filtered = data.filter(item =>
110
item.name.toLowerCase().includes(newFilter.toLowerCase())
111
);
112
113
const sorted = sortData(filtered, sortOrder);
114
setFilteredData(sorted);
115
});
116
};
117
118
const handleSort = (order) => {
119
setSortOrder(order);
120
121
startTransition(() => {
122
const sorted = sortData(filteredData, order);
123
setFilteredData(sorted);
124
});
125
};
126
127
return (
128
<div>
129
<div className="controls">
130
<input
131
value={filter}
132
onChange={(e) => handleFilterChange(e.target.value)}
133
placeholder="Filter data..."
134
/>
135
136
<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>
141
142
<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
```
156
157
### useTransition (Hook Version)
158
159
Hook version of startTransition that also provides pending state.
160
161
```javascript { .api }
162
/**
163
* Hook for managing transitions with pending state
164
* @returns Tuple with isPending boolean and startTransition function
165
*/
166
function useTransition(): [boolean, (callback: () => void) => void];
167
```
168
169
**Usage Examples:**
170
171
```javascript
172
import React, { useTransition, useState } from 'react';
173
174
// Search with loading indicator
175
function SearchWithStatus() {
176
const [query, setQuery] = useState('');
177
const [results, setResults] = useState([]);
178
const [isPending, startTransition] = useTransition();
179
180
const handleSearch = (newQuery) => {
181
setQuery(newQuery);
182
183
startTransition(() => {
184
// This will set isPending to true until updates complete
185
const searchResults = performExpensiveSearch(newQuery);
186
setResults(searchResults);
187
});
188
};
189
190
return (
191
<div>
192
<input
193
value={query}
194
onChange={(e) => handleSearch(e.target.value)}
195
placeholder="Search..."
196
/>
197
198
{isPending && (
199
<div className="search-pending">
200
<Spinner /> Searching...
201
</div>
202
)}
203
204
<SearchResults results={results} />
205
</div>
206
);
207
}
208
209
// Form with async validation
210
function AsyncForm() {
211
const [formData, setFormData] = useState({ email: '', username: '' });
212
const [errors, setErrors] = useState({});
213
const [isPending, startTransition] = useTransition();
214
215
const validateField = (field, value) => {
216
setFormData(prev => ({ ...prev, [field]: value }));
217
218
startTransition(() => {
219
// Async validation (API call)
220
validateFieldAsync(field, value).then(validationResult => {
221
setErrors(prev => ({
222
...prev,
223
[field]: validationResult.error
224
}));
225
});
226
});
227
};
228
229
return (
230
<form className={isPending ? 'validating' : ''}>
231
<div>
232
<input
233
type="email"
234
value={formData.email}
235
onChange={(e) => validateField('email', e.target.value)}
236
placeholder="Email"
237
/>
238
{errors.email && <span className="error">{errors.email}</span>}
239
</div>
240
241
<div>
242
<input
243
type="text"
244
value={formData.username}
245
onChange={(e) => validateField('username', e.target.value)}
246
placeholder="Username"
247
/>
248
{errors.username && <span className="error">{errors.username}</span>}
249
</div>
250
251
{isPending && <div className="validation-indicator">Validating...</div>}
252
253
<button type="submit" disabled={isPending || Object.keys(errors).length > 0}>
254
Submit
255
</button>
256
</form>
257
);
258
}
259
260
// Paginated data with smooth transitions
261
function PaginatedList({ data, itemsPerPage = 10 }) {
262
const [currentPage, setCurrentPage] = useState(1);
263
const [displayData, setDisplayData] = useState([]);
264
const [isPending, startTransition] = useTransition();
265
266
const changePage = (page) => {
267
// Immediate update for active page indicator
268
setCurrentPage(page);
269
270
// Transition for data loading/processing
271
startTransition(() => {
272
const startIndex = (page - 1) * itemsPerPage;
273
const endIndex = startIndex + itemsPerPage;
274
const pageData = data.slice(startIndex, endIndex);
275
276
// Simulate processing time for large datasets
277
setDisplayData(processDataForDisplay(pageData));
278
});
279
};
280
281
const totalPages = Math.ceil(data.length / itemsPerPage);
282
283
return (
284
<div>
285
<div className={`data-container ${isPending ? 'loading' : ''}`}>
286
{isPending && <div className="loading-overlay">Loading...</div>}
287
<DataList items={displayData} />
288
</div>
289
290
<Pagination
291
currentPage={currentPage}
292
totalPages={totalPages}
293
onPageChange={changePage}
294
disabled={isPending}
295
/>
296
</div>
297
);
298
}
299
```
300
301
### useDeferredValue
302
303
Defers updating a value until more urgent updates have completed.
304
305
```javascript { .api }
306
/**
307
* Defers value updates for performance optimization
308
* @param value - Value to defer
309
* @returns Deferred version of the value
310
*/
311
function useDeferredValue<T>(value: T): T;
312
```
313
314
**Usage Examples:**
315
316
```javascript
317
import React, { useDeferredValue, useState, useMemo } from 'react';
318
319
// Expensive list filtering
320
function ProductList({ products }) {
321
const [filter, setFilter] = useState('');
322
const deferredFilter = useDeferredValue(filter);
323
324
// Expensive filtering operation uses deferred value
325
const filteredProducts = useMemo(() => {
326
if (!deferredFilter) return products;
327
328
return products.filter(product =>
329
product.name.toLowerCase().includes(deferredFilter.toLowerCase()) ||
330
product.description.toLowerCase().includes(deferredFilter.toLowerCase()) ||
331
product.tags.some(tag => tag.toLowerCase().includes(deferredFilter.toLowerCase()))
332
);
333
}, [products, deferredFilter]);
334
335
return (
336
<div>
337
<input
338
value={filter} // Input stays responsive with immediate value
339
onChange={(e) => setFilter(e.target.value)}
340
placeholder="Filter products..."
341
/>
342
343
<div className="product-grid">
344
{filteredProducts.map(product => (
345
<ProductCard key={product.id} product={product} />
346
))}
347
</div>
348
</div>
349
);
350
}
351
352
// Chart with deferred data updates
353
function DataVisualization({ dataset, chartType }) {
354
const [zoomLevel, setZoomLevel] = useState(1);
355
const [selectedRange, setSelectedRange] = useState(null);
356
357
// Defer expensive data processing
358
const deferredZoom = useDeferredValue(zoomLevel);
359
const deferredRange = useDeferredValue(selectedRange);
360
361
const processedData = useMemo(() => {
362
// Expensive data processing for visualization
363
return processDataForChart(dataset, {
364
zoom: deferredZoom,
365
range: deferredRange,
366
type: chartType
367
});
368
}, [dataset, deferredZoom, deferredRange, chartType]);
369
370
return (
371
<div>
372
<div className="chart-controls">
373
<input
374
type="range"
375
min="0.5"
376
max="5"
377
step="0.1"
378
value={zoomLevel}
379
onChange={(e) => setZoomLevel(parseFloat(e.target.value))}
380
/>
381
<span>Zoom: {zoomLevel}x</span>
382
</div>
383
384
<Chart data={processedData} onRangeSelect={setSelectedRange} />
385
</div>
386
);
387
}
388
389
// Search results with deferred query
390
function SmartSearch() {
391
const [query, setQuery] = useState('');
392
const [category, setCategory] = useState('all');
393
const deferredQuery = useDeferredValue(query);
394
395
const searchResults = useMemo(() => {
396
if (!deferredQuery.trim()) return [];
397
398
// Expensive search across multiple data sources
399
return performComprehensiveSearch(deferredQuery, category);
400
}, [deferredQuery, category]);
401
402
const isStale = query !== deferredQuery;
403
404
return (
405
<div>
406
<div className="search-controls">
407
<input
408
value={query}
409
onChange={(e) => setQuery(e.target.value)}
410
placeholder="Search..."
411
/>
412
413
<select
414
value={category}
415
onChange={(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>
423
424
<div className={`search-results ${isStale ? 'stale' : ''}`}>
425
{isStale && (
426
<div className="search-updating">Updating results...</div>
427
)}
428
429
<SearchResults results={searchResults} />
430
</div>
431
</div>
432
);
433
}
434
435
// Complex form with deferred validation
436
function ComplexForm() {
437
const [formData, setFormData] = useState({
438
name: '',
439
email: '',
440
preferences: []
441
});
442
443
// Defer expensive validation
444
const deferredFormData = useDeferredValue(formData);
445
446
const validationResults = useMemo(() => {
447
return validateComplexForm(deferredFormData);
448
}, [deferredFormData]);
449
450
const isValidating = formData !== deferredFormData;
451
452
const updateField = (field, value) => {
453
setFormData(prev => ({ ...prev, [field]: value }));
454
};
455
456
return (
457
<form className={isValidating ? 'validating' : ''}>
458
<input
459
value={formData.name}
460
onChange={(e) => updateField('name', e.target.value)}
461
placeholder="Full Name"
462
/>
463
464
<input
465
value={formData.email}
466
onChange={(e) => updateField('email', e.target.value)}
467
placeholder="Email"
468
type="email"
469
/>
470
471
<PreferenceSelector
472
value={formData.preferences}
473
onChange={(prefs) => updateField('preferences', prefs)}
474
/>
475
476
{isValidating && <div className="validation-pending">Validating...</div>}
477
478
<ValidationSummary results={validationResults} />
479
480
<button
481
type="submit"
482
disabled={isValidating || !validationResults.isValid}
483
>
484
Submit
485
</button>
486
</form>
487
);
488
}
489
```
490
491
## Types
492
493
```javascript { .api }
494
// Concurrent feature types
495
function startTransition(scope: () => void): void;
496
497
function useTransition(): [boolean, (callback: () => void) => void];
498
499
function useDeferredValue<T>(value: T): T;
500
501
// Transition callback type
502
type TransitionCallback = () => void;
503
504
// Hook return types
505
type UseTransitionReturn = [boolean, (callback: TransitionCallback) => void];
506
```