Wyobraź sobie centrum kontroli misji na stacji kosmicznej, gdzie jednocześnie przetwarzane są setki sygnałów z różnych czujników. Niektóre dane są pilne (alarmy), inne mniej (statystyki pogodowe z odległych planet). React Concurrent Mode działa na podobnej zasadzie - pozwala priorytetyzować aktualizacje interfejsu, aby aplikacja pozostała responsywna nawet podczas ciężkich operacji.
Concurrent Mode (tryb współbieżny) to zestaw mechanizmów w React, które pozwalają na przerywanie i wznawianie renderowania. Tradycyjnie React renderował synchronicznie - gdy zaczynał aktualizację, musiał ją dokończyć, zanim mógł zareagować na cokolwiek innego. W trybie współbieżnym React może:
To jak kosmiczny kontroler, który może odłożyć analizę danych z dalekiej sondy, gdy nagle pojawi się alert o zbliżającej się asteroidzie.
startTransition to API, które mówi Reactowi: "ta aktualizacja nie jest pilna, możesz ją przerwać". Jest idealne dla operacji, które mogą chwilę poczekać, jak filtrowanie dużej listy czy nawigacja między zakładkami.1import { useState, startTransition } from 'react';
2
3function GalaxySearch() {
4 const [searchInput, setSearchInput] = useState('');
5 const [searchResults, setSearchResults] = useState([]);
6
7 const handleSearch = (value) => {
8 // Aktualizacja inputa jest PILNA - użytkownik musi widzieć co pisze
9 setSearchInput(value);
10
11 // Filtrowanie wyników jest MNIEJ PILNE
12 startTransition(() => {
13 const filtered = galaxyDatabase.filter(
14 galaxy => galaxy.name.toLowerCase().includes(value.toLowerCase())
15 );
16 setSearchResults(filtered);
17 });
18 };
19
20 return (
21 <div>
22 <input
23 value={searchInput}
24 onChange={(e) => handleSearch(e.target.value)}
25 placeholder="Szukaj galaktyk..."
26 />
27 <GalaxyList results={searchResults} />
28 </div>
29 );
30}Dzięki
startTransition input reaguje natychmiast na wpisywanie, nawet jeśli filtrowanie tysięcy galaktyk zajmuje chwilę.useTransition to hook, który oprócz startTransition daje nam flagę isPending, informującą, czy przejście jest w toku:1import { useState, useTransition } from 'react';
2
3function MissionDashboard() {
4 const [activeTab, setActiveTab] = useState('overview');
5 const [isPending, startTransition] = useTransition();
6
7 const switchTab = (tab) => {
8 startTransition(() => {
9 setActiveTab(tab);
10 });
11 };
12
13 return (
14 <div>
15 <nav>
16 {['overview', 'crew', 'systems', 'navigation'].map(tab => (
17 <button
18 key={tab}
19 onClick={() => switchTab(tab)}
20 style={{
21 opacity: isPending && activeTab !== tab ? 0.7 : 1,
22 fontWeight: activeTab === tab ? 'bold' : 'normal',
23 }}
24 >
25 {tab.toUpperCase()}
26 </button>
27 ))}
28 </nav>
29
30 {isPending && <div className="loading-bar">Ładowanie panelu...</div>}
31
32 <TabContent tab={activeTab} />
33 </div>
34 );
35}Suspense to komponent, który pozwala "zawiesić" renderowanie, dopóki dane nie będą gotowe. Zamiast ręcznie zarządzać stanami ładowania, deklarujesz co pokazać podczas oczekiwania:1import { Suspense } from 'react';
2
3function SpaceStation() {
4 return (
5 <div>
6 <h1>Stacja Kosmiczna Alpha</h1>
7
8 <Suspense fallback={<LoadingSpinner message="Ładowanie danych załogi..." />}>
9 <CrewList />
10 </Suspense>
11
12 <Suspense fallback={<LoadingSpinner message="Sprawdzanie systemów..." />}>
13 <SystemsStatus />
14 </Suspense>
15 </div>
16 );
17}Każda sekcja ładuje się niezależnie - użytkownik widzi dane załogi, gdy tylko będą gotowe, nie czekając na status systemów.
Najczęstsze zastosowanie Suspense to ładowanie komponentów dynamicznie za pomocą
React.lazy:1import { lazy, Suspense } from 'react';
2
3// Komponenty ładowane dynamicznie
4const StarMap = lazy(() => import('./StarMap'));
5const MissionLog = lazy(() => import('./MissionLog'));
6const CrewManagement = lazy(() => import('./CrewManagement'));
7
8function CommandCenter() {
9 const [view, setView] = useState('map');
10
11 return (
12 <div>
13 <nav>
14 <button onClick={() => setView('map')}>Mapa gwiazd</button>
15 <button onClick={() => setView('log')}>Dziennik misji</button>
16 <button onClick={() => setView('crew')}>Załoga</button>
17 </nav>
18
19 <Suspense fallback={<div>Ładowanie modułu...</div>}>
20 {view === 'map' && <StarMap />}
21 {view === 'log' && <MissionLog />}
22 {view === 'crew' && <CrewManagement />}
23 </Suspense>
24 </div>
25 );
26}Możemy zagnieżdżać komponenty
Suspense, tworząc hierarchię ładowania. Zewnętrzny Suspense łapie wszystko, wewnętrzne pozwalają na bardziej granularną kontrolę:1function MissionControl() {
2 return (
3 <Suspense fallback={<FullPageLoader />}>
4 <header>
5 <MissionTitle />
6 </header>
7
8 <main>
9 <Suspense fallback={<SectionLoader text="Mapa..." />}>
10 <InteractiveStarMap />
11 </Suspense>
12
13 <aside>
14 <Suspense fallback={<SectionLoader text="Statystyki..." />}>
15 <MissionStats />
16 </Suspense>
17
18 <Suspense fallback={<SectionLoader text="Komunikaty..." />}>
19 <CommunicationLog />
20 </Suspense>
21 </aside>
22 </main>
23 </Suspense>
24 );
25}useDeferredValue to hook, który pozwala opóźnić aktualizację wartości. React najpierw wyrenderuje z poprzednią wartością (pilna aktualizacja), a potem z nową (mniej pilna):1import { useState, useDeferredValue, useMemo } from 'react';
2
3function PlanetExplorer() {
4 const [filter, setFilter] = useState('');
5 const deferredFilter = useDeferredValue(filter);
6
7 // Lista renderuje się z opóźnioną wartością filtra
8 const filteredPlanets = useMemo(() => {
9 return allPlanets.filter(p =>
10 p.name.toLowerCase().includes(deferredFilter.toLowerCase())
11 );
12 }, [deferredFilter]);
13
14 const isStale = filter !== deferredFilter;
15
16 return (
17 <div>
18 <input
19 value={filter}
20 onChange={(e) => setFilter(e.target.value)}
21 placeholder="Filtruj planety..."
22 />
23 <div style={{ opacity: isStale ? 0.6 : 1 }}>
24 {filteredPlanets.map(planet => (
25 <PlanetCard key={planet.id} planet={planet} />
26 ))}
27 </div>
28 </div>
29 );
30}| API | Zastosowanie | Przykład | |-----|-------------|---------| |
startTransition | Aktualizacje, które mogą poczekać | Zmiana filtrów, nawigacja między zakładkami |
| useTransition | Jak wyżej + wskaźnik ładowania | Przełączanie widoków z loading state |
| Suspense | Oczekiwanie na dane lub kod | Lazy loading, pobieranie danych |
| useDeferredValue | Opóźnienie renderowania wartości | Filtrowanie dużych list, wyszukiwanie |Concurrent Mode i Suspense to jak zaawansowany system zarządzania priorytetami na stacji kosmicznej. Zamiast przetwarzać wszystkie sygnały sekwencyjnie (blokując ważne alerty na czas analizy mniej istotnych danych), React może inteligentnie priorytetyzować aktualizacje:
Te mechanizmy współpracują ze sobą, tworząc responsywne interfejsy nawet w złożonych aplikacjach z dużą ilością danych i ciężkimi operacjami.