Hook
useDeferredValue to uzupełnienie useTransition, które pozwala na "opóźnienie" wartości, dzięki czemu React może traktować aktualizacje jako mniej pilne. Jest szczególnie przydatny, gdy chcemy zachować responsywność UI podczas renderowania ciężkich komponentów.1import { useDeferredValue, useState } from 'react';
2
3function SearchApp() {
4 const [query, setQuery] = useState('');
5 const deferredQuery = useDeferredValue(query);
6
7 return (
8 <div>
9 <input
10 value={query}
11 onChange={(e) => setQuery(e.target.value)}
12 />
13
14 {/* Input aktualizuje się natychmiast */}
15 <p>Aktualne zapytanie: {query}</p>
16
17 {/* Lista używa opóźnionej wartości */}
18 <SearchResults query={deferredQuery} />
19 </div>
20 );
21}
22
23function SearchResults({ query }) {
24 // Ciężkie obliczenia z opóźnioną wartością
25 const results = performHeavySearch(query);
26
27 return (
28 <div>
29 <p>Wyniki dla: "{query}"</p>
30 <ul>
31 {results.map(result => (
32 <li key={result.id}>{result.title}</li>
33 ))}
34 </ul>
35 </div>
36 );
37}
38
39function performHeavySearch(query) {
40 // Symulacja ciężkich obliczeń
41 const items = [];
42 for (let i = 0; i < 5000; i++) {
43 if (`Item ${i}`.toLowerCase().includes(query.toLowerCase())) {
44 items.push({ id: i, title: `Item ${i}` });
45 }
46 }
47 return items;
48}1import { useDeferredValue, useTransition, useState } from 'react';
2
3// Podejście 1: useDeferredValue
4function DeferredValueExample() {
5 const [input, setInput] = useState('');
6 const deferredInput = useDeferredValue(input);
7
8 return (
9 <div>
10 <h3>useDeferredValue</h3>
11 <input
12 value={input}
13 onChange={(e) => setInput(e.target.value)}
14 />
15 <HeavyComponent text={deferredInput} />
16 </div>
17 );
18}
19
20// Podejście 2: useTransition
21function TransitionExample() {
22 const [input, setInput] = useState('');
23 const [deferredInput, setDeferredInput] = useState('');
24 const [isPending, startTransition] = useTransition();
25
26 const handleChange = (value) => {
27 setInput(value); // Natychmiastowa aktualizacja
28 startTransition(() => {
29 setDeferredInput(value); // Opóźniona aktualizacja
30 });
31 };
32
33 return (
34 <div>
35 <h3>useTransition</h3>
36 <input
37 value={input}
38 onChange={(e) => handleChange(e.target.value)}
39 />
40 {isPending && <div>Aktualizowanie...</div>}
41 <HeavyComponent text={deferredInput} />
42 </div>
43 );
44}
45
46function HeavyComponent({ text }) {
47 // Symulacja ciężkiego renderowania
48 const items = [];
49 for (let i = 0; i < 1000; i++) {
50 items.push(`${text} - element ${i}`);
51 }
52
53 return (
54 <div style={{ height: '200px', overflow: 'auto' }}>
55 {items.map((item, index) => (
56 <div key={index} style={{ padding: '2px' }}>
57 {item}
58 </div>
59 ))}
60 </div>
61 );
62}
63
64// Porównanie obu podejść
65function ComparisonDemo() {
66 return (
67 <div style={{ display: 'flex', gap: '20px' }}>
68 <div style={{ flex: 1 }}>
69 <DeferredValueExample />
70 </div>
71 <div style={{ flex: 1 }}>
72 <TransitionExample />
73 </div>
74 </div>
75 );
76}1import { useDeferredValue, useState, memo } from 'react';
2
3// Komponent zoptymalizowany z memo
4const OptimizedList = memo(function OptimizedList({ items, highlightTerm }) {
5 console.log('OptimizedList renderuje się dla:', highlightTerm);
6
7 return (
8 <div style={{ height: '300px', overflow: 'auto', border: '1px solid #ddd' }}>
9 {items.map(item => (
10 <div
11 key={item.id}
12 style={{
13 padding: '8px',
14 borderBottom: '1px solid #eee',
15 backgroundColor: item.id % 2 === 0 ? '#f9f9f9' : '#fff'
16 }}
17 >
18 <strong>
19 {highlightText(item.title, highlightTerm)}
20 </strong>
21 <div style={{ fontSize: '14px', color: '#666' }}>
22 {highlightText(item.description, highlightTerm)}
23 </div>
24 </div>
25 ))}
26 </div>
27 );
28});
29
30function SearchWithOptimization() {
31 const [searchTerm, setSearchTerm] = useState('');
32 const deferredSearchTerm = useDeferredValue(searchTerm);
33
34 // Generowanie danych
35 const allItems = generateSearchData(2000);
36
37 // Filtrowanie z opóźnioną wartością
38 const filteredItems = allItems.filter(item =>
39 item.title.toLowerCase().includes(deferredSearchTerm.toLowerCase()) ||
40 item.description.toLowerCase().includes(deferredSearchTerm.toLowerCase())
41 );
42
43 const isStale = searchTerm !== deferredSearchTerm;
44
45 return (
46 <div style={{ maxWidth: '600px', margin: '0 auto', padding: '20px' }}>
47 <h2>Wyszukiwarka z useDeferredValue</h2>
48
49 <input
50 value={searchTerm}
51 onChange={(e) => setSearchTerm(e.target.value)}
52 style={{
53 width: '100%',
54 padding: '12px',
55 fontSize: '16px',
56 border: '2px solid #ddd',
57 borderRadius: '8px',
58 marginBottom: '10px'
59 }}
60 />
61
62 <div style={{
63 display: 'flex',
64 justifyContent: 'space-between',
65 alignItems: 'center',
66 marginBottom: '10px',
67 fontSize: '14px'
68 }}>
69 <span>
70 Znaleziono {filteredItems.length} wyników
71 {deferredSearchTerm && ` dla "${deferredSearchTerm}"`}
72 </span>
73
74 {isStale && (
75 <span style={{ color: '#007bff', fontStyle: 'italic' }}>
76 🔄 Aktualizowanie...
77 </span>
78 )}
79 </div>
80
81 <div style={{ opacity: isStale ? 0.7 : 1, transition: 'opacity 0.2s' }}>
82 <OptimizedList
83 items={filteredItems}
84 highlightTerm={deferredSearchTerm}
85 />
86 </div>
87 </div>
88 );
89}
90
91function generateSearchData(count) {
92 const categories = ['Elektronika', 'Książki', 'Odzież', 'Dom', 'Sport'];
93 const adjectives = ['Nowoczesny', 'Klasyczny', 'Premium', 'Ekonomiczny', 'Uniwersalny'];
94
95 return Array.from({ length: count }, (_, i) => ({
96 id: i,
97 title: `${adjectives[i % adjectives.length]} Produkt ${i + 1}`,
98 description: `Opis produktu z kategorii ${categories[i % categories.length]}. Wysokiej jakości artykuł.`,
99 category: categories[i % categories.length],
100 price: Math.floor(Math.random() * 1000) + 50
101 }));
102}
103
104function highlightText(text, term) {
105 if (!term) return text;
106
107 const regex = new RegExp(`(${term})`, 'gi');
108 const parts = text.split(regex);
109
110 return parts.map((part, index) =>
111 part.toLowerCase() === term.toLowerCase() ? (
112 <mark key={index} style={{ backgroundColor: '#ffeb3b', padding: '2px' }}>
113 {part}
114 </mark>
115 ) : part
116 );
117}1import { useDeferredValue, useState, Suspense } from 'react';
2
3function AdaptiveLoadingDemo() {
4 const [selectedTab, setSelectedTab] = useState('popular');
5 const deferredTab = useDeferredValue(selectedTab);
6
7 const tabs = [
8 { id: 'popular', label: 'Popularne', icon: '🔥' },
9 { id: 'newest', label: 'Najnowsze', icon: '🆕' },
10 { id: 'trending', label: 'Trending', icon: '📈' }
11 ];
12
13 return (
14 <div style={{ maxWidth: '800px', margin: '0 auto', padding: '20px' }}>
15 <h2>Adaptive Loading z useDeferredValue</h2>
16
17 {/* Tab Navigation */}
18 <div style={{
19 display: 'flex',
20 marginBottom: '20px',
21 borderBottom: '1px solid #ddd'
22 }}>
23 {tabs.map(tab => (
24 <button
25 key={tab.id}
26 onClick={() => setSelectedTab(tab.id)}
27 style={{
28 padding: '12px 20px',
29 border: 'none',
30 backgroundColor: selectedTab === tab.id ? '#007bff' : 'transparent',
31 color: selectedTab === tab.id ? 'white' : '#007bff',
32 cursor: 'pointer',
33 borderRadius: '8px 8px 0 0',
34 marginRight: '5px',
35 fontSize: '16px'
36 }}
37 >
38 {tab.icon} {tab.label}
39 </button>
40 ))}
41 </div>
42
43 {/* Content with deferred loading */}
44 <div style={{ position: 'relative' }}>
45 {/* Show loading state when tab is changing */}
46 {selectedTab !== deferredTab && (
47 <div style={{
48 position: 'absolute',
49 top: 0,
50 left: 0,
51 right: 0,
52 bottom: 0,
53 backgroundColor: 'rgba(255, 255, 255, 0.8)',
54 display: 'flex',
55 alignItems: 'center',
56 justifyContent: 'center',
57 zIndex: 1,
58 borderRadius: '8px'
59 }}>
60 <div style={{
61 padding: '20px',
62 backgroundColor: 'white',
63 borderRadius: '8px',
64 boxShadow: '0 2px 10px rgba(0,0,0,0.1)'
65 }}>
66 🔄 Ładowanie zawartości...
67 </div>
68 </div>
69 )}
70
71 <Suspense fallback={<TabContentSkeleton />}>
72 <TabContent tab={deferredTab} />
73 </Suspense>
74 </div>
75 </div>
76 );
77}
78
79function TabContent({ tab }) {
80 // Symulacja ciężkiego ładowania danych
81 const content = generateTabContent(tab);
82
83 return (
84 <div style={{
85 minHeight: '400px',
86 padding: '20px',
87 backgroundColor: '#f8f9fa',
88 borderRadius: '8px'
89 }}>
90 <h3>Zawartość zakładki: {tab}</h3>
91 <div style={{ display: 'grid', gap: '15px' }}>
92 {content.map(item => (
93 <div
94 key={item.id}
95 style={{
96 padding: '15px',
97 backgroundColor: 'white',
98 borderRadius: '6px',
99 boxShadow: '0 1px 3px rgba(0,0,0,0.1)'
100 }}
101 >
102 <h4 style={{ margin: '0 0 8px 0', color: '#333' }}>
103 {item.title}
104 </h4>
105 <p style={{ margin: 0, color: '#666', fontSize: '14px' }}>
106 {item.description}
107 </p>
108 <div style={{
109 marginTop: '8px',
110 fontSize: '12px',
111 color: '#999'
112 }}>
113 {item.date} • {item.views} wyświetleń
114 </div>
115 </div>
116 ))}
117 </div>
118 </div>
119 );
120}
121
122function TabContentSkeleton() {
123 return (
124 <div style={{
125 minHeight: '400px',
126 padding: '20px',
127 backgroundColor: '#f8f9fa',
128 borderRadius: '8px'
129 }}>
130 <div style={{
131 height: '24px',
132 backgroundColor: '#e9ecef',
133 borderRadius: '4px',
134 marginBottom: '20px',
135 width: '200px'
136 }} />
137
138 {Array.from({ length: 5 }).map((_, i) => (
139 <div
140 key={i}
141 style={{
142 padding: '15px',
143 backgroundColor: 'white',
144 borderRadius: '6px',
145 marginBottom: '15px',
146 boxShadow: '0 1px 3px rgba(0,0,0,0.1)'
147 }}
148 >
149 <div style={{
150 height: '18px',
151 backgroundColor: '#e9ecef',
152 borderRadius: '4px',
153 marginBottom: '8px',
154 width: '70%'
155 }} />
156 <div style={{
157 height: '14px',
158 backgroundColor: '#f1f3f4',
159 borderRadius: '4px',
160 marginBottom: '4px'
161 }} />
162 <div style={{
163 height: '14px',
164 backgroundColor: '#f1f3f4',
165 borderRadius: '4px',
166 width: '60%'
167 }} />
168 </div>
169 ))}
170 </div>
171 );
172}
173
174function generateTabContent(tab) {
175 const contentMap = {
176 popular: [
177 { id: 1, title: 'Najpopularniejszy artykuł', description: 'Ten artykuł cieszył się największą popularnością w tym tygodniu.', date: '2024-01-15', views: 15420 },
178 { id: 2, title: 'Drugi w rankingu', description: 'Świetny materiał, który zdobył uznanie czytelników.', date: '2024-01-14', views: 12380 },
179 { id: 3, title: 'Top 3 popularności', description: 'Również bardzo ciekawy artykuł z wysoką oceną.', date: '2024-01-13', views: 9560 }
180 ],
181 newest: [
182 { id: 4, title: 'Najnowszy post', description: 'Świeżo opublikowany materiał na blogu.', date: '2024-01-16', views: 245 },
183 { id: 5, title: 'Wczorajszy artykuł', description: 'Opublikowany wczoraj, już zyskuje popularność.', date: '2024-01-15', views: 1230 },
184 { id: 6, title: 'Sprzed 2 dni', description: 'Nadal aktualny i wartościowy materiał.', date: '2024-01-14', views: 2100 }
185 ],
186 trending: [
187 { id: 7, title: 'Viral na social media', description: 'Ten artykuł podbija social media!', date: '2024-01-12', views: 25600 },
188 { id: 8, title: 'Rosnąca popularność', description: 'Szybko zyskuje na popularności.', date: '2024-01-11', views: 8970 },
189 { id: 9, title: 'Trend tygodnia', description: 'Główny trend tego tygodnia w naszej branży.', date: '2024-01-10', views: 14520 }
190 ]
191 };
192
193 return contentMap[tab] || [];
194}1import { useDeferredValue, useState, useEffect, useMemo } from 'react';
2
3function SmartFilteringDemo() {
4 const [searchQuery, setSearchQuery] = useState('');
5 const [priceRange, setPriceRange] = useState([0, 1000]);
6 const [category, setCategory] = useState('all');
7
8 // Opóźnione wartości dla ciężkich operacji
9 const deferredQuery = useDeferredValue(searchQuery);
10 const deferredPriceRange = useDeferredValue(priceRange);
11 const deferredCategory = useDeferredValue(category);
12
13 // Sprawdzenie czy filtrowanie jest w toku
14 const isFiltering =
15 searchQuery !== deferredQuery ||
16 priceRange !== deferredPriceRange ||
17 category !== deferredCategory;
18
19 const products = useMemo(() => generateProducts(1000), []);
20
21 // Filtrowanie z opóźnionymi wartościami
22 const filteredProducts = useMemo(() => {
23 return products.filter(product => {
24 const matchesSearch = product.name.toLowerCase().includes(deferredQuery.toLowerCase()) ||
25 product.description.toLowerCase().includes(deferredQuery.toLowerCase());
26
27 const matchesPrice = product.price >= deferredPriceRange[0] &&
28 product.price <= deferredPriceRange[1];
29
30 const matchesCategory = deferredCategory === 'all' ||
31 product.category === deferredCategory;
32
33 return matchesSearch && matchesPrice && matchesCategory;
34 });
35 }, [products, deferredQuery, deferredPriceRange, deferredCategory]);
36
37 return (
38 <div style={{ maxWidth: '1200px', margin: '0 auto', padding: '20px' }}>
39 <h2>Smart Filtering z useDeferredValue</h2>
40
41 <div style={{
42 display: 'grid',
43 gridTemplateColumns: '300px 1fr',
44 gap: '20px'
45 }}>
46 {/* Filters Sidebar */}
47 <div style={{
48 padding: '20px',
49 backgroundColor: '#f8f9fa',
50 borderRadius: '8px',
51 height: 'fit-content'
52 }}>
53 <h3 style={{ marginTop: 0 }}>Filtry</h3>
54
55 {/* Search Filter */}
56 <div style={{ marginBottom: '20px' }}>
57 <label style={{ display: 'block', marginBottom: '5px', fontWeight: 'bold' }}>
58 Szukaj:
59 </label>
60 <input
61 value={searchQuery}
62 onChange={(e) => setSearchQuery(e.target.value)}
63 style={{
64 width: '100%',
65 padding: '8px',
66 border: '1px solid #ddd',
67 borderRadius: '4px'
68 }}
69 />
70 </div>
71
72 {/* Category Filter */}
73 <div style={{ marginBottom: '20px' }}>
74 <label style={{ display: 'block', marginBottom: '5px', fontWeight: 'bold' }}>
75 Kategoria:
76 </label>
77 <select
78 value={category}
79 onChange={(e) => setCategory(e.target.value)}
80 style={{
81 width: '100%',
82 padding: '8px',
83 border: '1px solid #ddd',
84 borderRadius: '4px'
85 }}
86 >
87 <option value="all">Wszystkie</option>
88 <option value="Electronics">Elektronika</option>
89 <option value="Books">Książki</option>
90 <option value="Clothing">Odzież</option>
91 <option value="Home">Dom</option>
92 </select>
93 </div>
94
95 {/* Price Range Filter */}
96 <div style={{ marginBottom: '20px' }}>
97 <label style={{ display: 'block', marginBottom: '5px', fontWeight: 'bold' }}>
98 Cena: {priceRange[0]} - {priceRange[1]} zł
99 </label>
100 <input
101 type="range"
102 min="0"
103 max="1000"
104 value={priceRange[1]}
105 onChange={(e) => setPriceRange([priceRange[0], parseInt(e.target.value)])}
106 style={{ width: '100%' }}
107 />
108 </div>
109
110 {/* Filter Status */}
111 <div style={{
112 padding: '10px',
113 backgroundColor: isFiltering ? '#fff3cd' : '#d4edda',
114 borderRadius: '4px',
115 fontSize: '14px',
116 textAlign: 'center'
117 }}>
118 {isFiltering ? (
119 <span>🔄 Filtrowanie...</span>
120 ) : (
121 <span>✅ Gotowe</span>
122 )}
123 </div>
124 </div>
125
126 {/* Results */}
127 <div>
128 <div style={{
129 display: 'flex',
130 justifyContent: 'space-between',
131 alignItems: 'center',
132 marginBottom: '20px'
133 }}>
134 <h3 style={{ margin: 0 }}>
135 Produkty ({filteredProducts.length})
136 </h3>
137
138 {isFiltering && (
139 <span style={{ color: '#007bff', fontSize: '14px' }}>
140 Aktualizowanie wyników...
141 </span>
142 )}
143 </div>
144
145 <div style={{
146 opacity: isFiltering ? 0.7 : 1,
147 transition: 'opacity 0.3s',
148 display: 'grid',
149 gridTemplateColumns: 'repeat(auto-fill, minmax(250px, 1fr))',
150 gap: '15px'
151 }}>
152 {filteredProducts.slice(0, 20).map(product => (
153 <div
154 key={product.id}
155 style={{
156 padding: '15px',
157 backgroundColor: 'white',
158 border: '1px solid #e9ecef',
159 borderRadius: '8px',
160 boxShadow: '0 1px 3px rgba(0,0,0,0.1)'
161 }}
162 >
163 <h4 style={{ margin: '0 0 8px 0', fontSize: '16px' }}>
164 {highlightText(product.name, deferredQuery)}
165 </h4>
166 <p style={{
167 margin: '0 0 8px 0',
168 fontSize: '14px',
169 color: '#666',
170 lineHeight: '1.4'
171 }}>
172 {highlightText(product.description, deferredQuery)}
173 </p>
174 <div style={{
175 display: 'flex',
176 justifyContent: 'space-between',
177 alignItems: 'center',
178 fontSize: '14px'
179 }}>
180 <span style={{
181 backgroundColor: '#e9ecef',
182 padding: '2px 6px',
183 borderRadius: '4px',
184 fontSize: '12px'
185 }}>
186 {product.category}
187 </span>
188 <span style={{
189 fontWeight: 'bold',
190 color: '#007bff',
191 fontSize: '16px'
192 }}>
193 {product.price} zł
194 </span>
195 </div>
196 </div>
197 ))}
198 </div>
199
200 {filteredProducts.length === 0 && (
201 <div style={{
202 textAlign: 'center',
203 padding: '40px',
204 color: '#666'
205 }}>
206 Brak produktów spełniających kryteria
207 </div>
208 )}
209 </div>
210 </div>
211 </div>
212 );
213}
214
215function generateProducts(count) {
216 const categories = ['Electronics', 'Books', 'Clothing', 'Home'];
217 const adjectives = ['Premium', 'Classic', 'Modern', 'Vintage', 'Professional'];
218 const nouns = ['Device', 'Tool', 'Item', 'Product', 'Gadget'];
219
220 return Array.from({ length: count }, (_, i) => ({
221 id: i,
222 name: `${adjectives[i % adjectives.length]} ${nouns[i % nouns.length]} ${i + 1}`,
223 description: `High-quality ${categories[i % categories.length].toLowerCase()} item with excellent features and durability.`,
224 category: categories[i % categories.length],
225 price: Math.floor(Math.random() * 950) + 50
226 }));
227}
228
229function highlightText(text, term) {
230 if (!term) return text;
231
232 const regex = new RegExp(`(${term})`, 'gi');
233 const parts = text.split(regex);
234
235 return parts.map((part, index) =>
236 part.toLowerCase() === term.toLowerCase() ? (
237 <mark key={index} style={{ backgroundColor: '#ffeb3b', padding: '1px' }}>
238 {part}
239 </mark>
240 ) : part
241 );
242}1// ✅ DOBRZE - Ciężkie listy i filtrowanie
2function ProductSearch() {
3 const [query, setQuery] = useState('');
4 const deferredQuery = useDeferredValue(query);
5
6 return (
7 <>
8 <input value={query} onChange={e => setQuery(e.target.value)} />
9 <HeavyProductList searchTerm={deferredQuery} />
10 </>
11 );
12}
13
14// ✅ DOBRZE - Renderowanie wykresów
15function ChartDashboard() {
16 const [dateRange, setDateRange] = useState([startDate, endDate]);
17 const deferredDateRange = useDeferredValue(dateRange);
18
19 return (
20 <>
21 <DateRangePicker onChange={setDateRange} />
22 <ExpensiveChart dateRange={deferredDateRange} />
23 </>
24 );
25}
26
27// ❌ ŹLE - Proste operacje
28function SimpleCounter() {
29 const [count, setCount] = useState(0);
30 const deferredCount = useDeferredValue(count); // Niepotrzebne!
31
32 return <div>{deferredCount}</div>;
33}1import { useDeferredValue, useState, useMemo, useCallback } from 'react';
2
3function OptimizedDataTable() {
4 const [searchTerm, setSearchTerm] = useState('');
5 const [sortConfig, setSortConfig] = useState({ field: 'name', direction: 'asc' });
6
7 const deferredSearchTerm = useDeferredValue(searchTerm);
8 const deferredSortConfig = useDeferredValue(sortConfig);
9
10 const data = useMemo(() => generateLargeDataset(5000), []);
11
12 // Memoized filtering and sorting
13 const processedData = useMemo(() => {
14 let filtered = data;
15
16 if (deferredSearchTerm) {
17 filtered = data.filter(item =>
18 item.name.toLowerCase().includes(deferredSearchTerm.toLowerCase())
19 );
20 }
21
22 return filtered.sort((a, b) => {
23 const direction = deferredSortConfig.direction === 'asc' ? 1 : -1;
24 return a[deferredSortConfig.field].localeCompare(b[deferredSortConfig.field]) * direction;
25 });
26 }, [data, deferredSearchTerm, deferredSortConfig]);
27
28 const handleSort = useCallback((field) => {
29 setSortConfig(prev => ({
30 field,
31 direction: prev.field === field && prev.direction === 'asc' ? 'desc' : 'asc'
32 }));
33 }, []);
34
35 const isStale = searchTerm !== deferredSearchTerm || sortConfig !== deferredSortConfig;
36
37 return (
38 <div>
39 <input
40 value={searchTerm}
41 onChange={(e) => setSearchTerm(e.target.value)}
42 />
43
44 <table style={{ opacity: isStale ? 0.7 : 1 }}>
45 <thead>
46 <tr>
47 <th onClick={() => handleSort('name')}>Nazwa</th>
48 <th onClick={() => handleSort('category')}>Kategoria</th>
49 <th onClick={() => handleSort('price')}>Cena</th>
50 </tr>
51 </thead>
52 <tbody>
53 {processedData.slice(0, 50).map(item => (
54 <tr key={item.id}>
55 <td>{item.name}</td>
56 <td>{item.category}</td>
57 <td>{item.price}</td>
58 </tr>
59 ))}
60 </tbody>
61 </table>
62 </div>
63 );
64}1// ❌ ŹLE - Nadmierne użycie
2function OverusedDeferred() {
3 const [name, setName] = useState('');
4 const [age, setAge] = useState(0);
5 const [email, setEmail] = useState('');
6
7 // Nie każda wartość potrzebuje deferred!
8 const deferredName = useDeferredValue(name);
9 const deferredAge = useDeferredValue(age);
10 const deferredEmail = useDeferredValue(email);
11
12 return <SimpleForm name={deferredName} age={deferredAge} email={deferredEmail} />;
13}
14
15// ✅ LEPIEJ - Selektywne użycie
16function BetterApproach() {
17 const [formData, setFormData] = useState({ name: '', age: 0, email: '' });
18 const deferredFormData = useDeferredValue(formData);
19
20 return <HeavyValidationForm data={deferredFormData} />;
21}useDeferredValue to elegancki sposób na poprawę wydajności aplikacji React bez skomplikowanego zarządzania stanem. Pozwala na zachowanie responsywności krytycznych elementów UI podczas wykonywania ciężkich operacji w tle.