30.03.20224 min

Maciej OlanickiRedakcja Bulldogjob

React 18 już jest! Do biblioteki zawitał tryb współbieżności

Dostępny jest już React 18. Od premiery poprzedniego dużego wydania upłynęło niemal półtora roku, developerzy mają więc prawo oczekiwać sporych nowości. I się nie zawiodą.

React 18 już jest! Do biblioteki zawitał tryb współbieżności

React to najpopularniejszy javascriptowa biblioteka, co potwierdza również raport z przeprowadzonych przez Bulldogjob Badań Społeczności IT. Według danych zebranych od ponad 8 tys. badanych wynika, że Reacta korzysta aż 61% Developerów JavaScript. Dla porównania można wskazać, że plasujący się na drugim miejscu Vue wykorzystuje zaledwie 19% programistów. Tym bardziej warto śledzić zmiany pojawiające się w kolejnych nowych wersjach Reacta.


Concurrent Rendering Mode, czyli współbieżność

A tych, jak już wspomniano, jest bardzo wiele. I są to zmiany ważne. Bodaj najwyraźniej sygnalizowana z nich nie jest jednak do końca nową funkcją użytkową, co raczej mechanizmem działającym pod maską Reacta i przyjął nazwę Concurrent React. 

W praktyce mowa tu o umożliwieniu renderowania współbieżnego. Wykorzystano do tego złożone mechanizmy, m.in. kolejki priorytetów czy buforowanie wielokrotne, niemniej wszystko odbywa się wewnątrz biblioteki, nie wystawia żadnych publicznych API i sama znajomość tego, jak realizowana jest współbieżność „w środku” Reakta nie jest potrzebna developerom.

Dlaczego to tak ważne? W trybie współbieżnym React może przerwać renderowanie. Może je wstrzymać i wznowić. Może jest także w ogóle porzucić. Zrobi to jednak dopiero po przeprowadzeniu mutacji DOM, dzięki czemu całość UI zostanie poprawnie wyrenderowana. Możliwość przerwania dotąd nienaruszalnego procesu umożliwia Reactowi renderowanie w tle przy odciążeniu głównego wątku. Wnioski nasuwają się same – React 18 wprowadzi duże – twórcy nie boją się nawet słowa „przełomowe” – zmiany w wydajności renderowania i ogólnej responsywności interfejsów.

Nowa wersja biblioteki to jednak dopiero początek na drodze do szerokiej implementacji współbieżności renderowania. Na razie developerzy mogą wykorzystywać pojedyncze mechanizmy. Na przykład funkcję startTransition pozwalającą wskazywać aktualizacje DOM, które mają zostać odroczone czy useDeferredValue, dzięki której można spowolnić najbardziej wymagające procesy renderowania. 

Więcej na temat praktyki użycia trybu współbieżności w Reakcie łmożna przeczytać w dotychczasowej dokumentacji wersji alpha dostępnej tutaj


Suspense i komponenty serwerowe

Kolejne dwie ważne nowości są w fazie eksperymentalnej i – jak deklarują sami twórcy – nie nadają się jeszcze do użytkowania na produkcji. Ich rozwój będzie kontynuowany i zawitają w stabilnej wersji do którejś z kolejnych wersji Reacta.

W Reakcie możliwe jest wstrzymywanie procesu pobierania danych w takich frameworkach jak Relay, Next.js czy Remix. Korzystanie z komponentu Suspense jest już co prawda możliwe także bezpośrednio, ale twórcy Reakta na razie stanowczo odradzają tę metodę. Dzięki Suspense można wskazać wydarzenie, dopiero po którym komponenty będą mogły się renderować. Mechanizm umożliwi przekazanie do bibliotek pobierających dane informacji, że dane, które w danym momencie są odczytywane, nie są jeszcze gotowe, a następnie wydać polecenie oczekiwania, aż dane będą gotowe.

Drugą dużą nowością, która na razie jest w fazie eksperymentalnej, są komponenty serwerowe. Ich stabilna wersja ma się pojawić już w jednej z mniejszych aktualizacji Reakta 18. Dzięki nowym komponentom React umożliwia renderowanie po stronie serwera.  W przyszłości to posłuży do swojego rodzaju renderowania hybrydowego, gdzie część procesów odbędzie się po stronie serwera, a część u klienta. Ma to przełożyć się na połączenie dużych możliwości klientów z serwerową wydajnością.


Automatyczne grupowanie

W najnowszej wersji Reakta możliwe jest grupowanie procesów aktualizacji wielu stanów. Przełoży się to na wydajność całego renderowania, gdyż cała grupa będzie aktualizować jednocześnie, w jednym procesie. Można to prześledzić na dostarczonym przez twórców przykładzie: 

// Wcześniej: tylko eventy były grupowane
setTimeout(() => {
  setCount(c => c + 1);
  setFlag(f => !f);
  // Konieczne są dwa rendery, na każdą aktualizację stanu (bez grupowania)
}, 1000);

// Teraz: aktualizacje wewnątrz timeoutów, obietnice czy dowolne wydarzenia są automatycznie zgrupowane.
setTimeout(() => {
  setCount(c => c + 1);
  setFlag(f => !f);
  // React wyrenderuje tylko raz (grupowanie)
}, 1000);


Przejścia

Kolejną nowością jest możliwość ustalenia, które aktualizacje interfejsu są pilne, a które mają niższy priorytet, czyli są tzw. przejściami. Jako przykład pilnych aktualizacji można uznać na przykład klikanie czy wpisywanie znaków przez użytkownika, zaś jako aktualizacje typu transition, mające niższy priorytet to np. przejście z jednego interfejsu do drugiego. 

Twórcy ciekawie argumentują to rozróżnienie tym, że niektóre elementy muszą renderować się natychmiastowo, gdyż inaczej podupada UX: złe wrażenie robi np. opóźnienie w pojawianiu się wpisanych znaków w polu. To właśnie dla takich sytuacji można ustalić pilny priorytet. Zaś do nieco dłuższego czasu oczekiwania na przejście z jednego interfejsu do drugiego użytkownicy i tak są przyzwyczajeni, dzięki czemu proces ten nie jest najpilniejszy. 

Praktykę można prześledzić na przykładzie rozróżniającym priorytet właśnie inputu od użytkownika z mniej pilnym wyświetleniem wyników wyszukiwania:

import {startTransition} from 'react';

// Pilne: pokazuj, co jest wpisywane
setInputValue(input);

// Oznacz dowolną aktualizację stanu jako przejście
startTransition(() => {
  // Przejście: pokaż rezultaty
  setSearchQuery(input);
});


Nowe hooki i inne nowości

Nowa wersja Recta przynosi także nowe hooki. Tym razem pojawiło się ich łącznie sześć, a po części odnoszą się do wspomnianych już nowości, np. useTransition i startTransition pozwala na wskazywanie pilnych aktualizacji i aktualizacji przejść. Ponadto do dyspozycji developerów oddano useId, generujący unikatowe ID po stronie klienta i serwera, ale z uniknięciem niedopasowania hydracji,  useDeferredValue , który pozwala przesunąć w czasie mało istotne aktualizacje drzewa w sposób podobny do debouncingu. Oprócz tego na potrzeby bibliotek dodano hooki useSyncExternalStore oraz useInsertionEffect.

Jak wspominano już na początku tego omówienia, React 18 to duże, wręcz ogromne wydanie z ważnymi zmianami, na czele ze współbieżnością. Części nowości nie udało się dowieść, ale choćby w przypadku komponentów serwerowych otrzymaliśmy deklarację, że pojawią się one wkrótce. React rozwija się prężnie, z wydania na wydanie wprowadza błyskotliwe mechanizmy optymalizacji renderowania, co przekłada się nie tylko na same interfejsy, ale też na user experience. Nie zapowiada się więc, aby dominującej pozycji rozwijanej przez Facebooka biblioteki miało w najbliższej przyszłości cokolwiek zagrozić.

<p>Loading...</p>