Zrozumienie niestandardowych hooków w React: ponowne użycie logiki bez wspólnego stanu
Dowiedz się, czym są niestandardowe hooki w React, jak wyodrębniają i udostępniają logikę związанą ze stanem pomiędzy komponentami oraz jakich częstych błędów należy unikać podczas ich tworzenia.
Wprowadzenie
Czy kiedykolwiek zdarzyło ci się pisać tę samą parę funkcji useState i useEffect w trzech różnych komponentach, zmieniając tylko nazwy zmiennych za każdym razem? Prawie każdy deweloper React spotyka się z tym w pewnym momencie. Kod działa poprawnie, ale oznacza to, że identyczna logika jest duplikowana w całym kodzie, a każda kopia z czasem zaczyna się różnić w wyniku niezależnych modyfikacji.
To właśnie taka sytuacja była celem stworzenia hooków niestandardowych w React. dokumentacja React na ten temat wyjaśnia, że przeniesienie zachowania komponentu do dedykowanej, wielokrotnie używalnej funkcji umożliwia poszczególnym częściom aplikacji dzielenie się tym samym zachowaniem związanym ze stanem, zamiast ciągle kopiować podstawową implementację. W tej części artykułu omówiono, czym właściwie są hooki niestandardowe, jak zachowują się w rzeczywistym kodzie oraz jakie są ich zalety i zagrożenia, które należy zrozumieć przed stworzeniem własnych.
Czym są hooki niestandardowe w React?
W istocie, niestandardowy hook to nic innego jak funkcja JavaScript, która podlega jednej ścisłej zasadzie nazewnictwa: jej nazwa musi zaczynać się od use. Wewnątrz może ona wywoływać inne hooks, takie jak useState lub useEffect, i zwracać wszystkie wartości lub funkcje potrzebne komponentowi, który ją wywołał. Sam React nie traktuje tej funkcji w żaden specjalny sposób podczas wykonywania — przedrostek use jest czysto konwencjonalny, ale niezwykle ważny, ponieważ umożliwia Reactowi prawidłowe egzekwowanie zasad hooków oraz pozwala innym programistom natychmiast rozpoznać, do czego służy dana funkcja.
Niestandardowe hooks a zwykłe funkcje
Standardowa funkcja pomocnicza może wykonywać wiele przydatnych zadań, ale nie może wywoływać innych hooków, ponieważ znajduje się poza mechanizmem renderowania React. Hook dostosowany pod potrzeby użytkownika nie ma takiej ograniczenia. To właśnie jest jego zaleta: można zamknąć w nim zachowania związane ze stanem — takie jak śledzenie flagi ładowania, obsługa zdarzeń przeglądarki czy cokolwiek podobnego — w coś wielokrotnie używalnego, które nadal idealnie pasuje do cyklu życia komponentu w React.
Jak działają hooki dostosowane pod potrzeby użytkownika w React
Konkretne przykład wyjaśnia to znacznie szybciej niż jakakolwiek abstrakcyjna explicacja.
Wyodrębnianie logiki z komponentu
Załóżmy trzy niepowiązane ze sobą komponenty, z których każdy musi sprawdzić, czy przeglądarka ma obecnie połączenie sieciowe. Bez wspólnego hooka każdy z nich musiałby sam stworzyć własne konfiguracje useState i useEffect, aby to monitorować:
function StatusBadge() {
const [isOnline, setIsOnline] = useState(navigator.onLine);
useEffect(() => {
const goOnline = () => setIsOnline(true);
const goOffline = () => setIsOnline(false);
window.addEventListener('online', goOnline);
window.addEventListener('offline', goOffline);
return () => {
window.removeEventListener('online', goOnline);
window.removeEventListener('offline', goOffline);
};
}, []);
return <span>{isOnline ? 'Online' : 'Offline'}</span>;
}
Zamiast tego można przenieść tę logikę do pojedynczego, dostosowanego hooka, a od tego momentu każdy komponent, który potrzebuje statusu, po prostu go wywołuje:
function useOnlineStatus() {
const [isOnline, setIsOnline] = useState(navigator.onLine);
useEffect(() => {
const goOnline = () => setIsOnline(true);
const goOffline = () => setIsOnline(false);
window.addEventListener('online', goOnline);
window.addEventListener('offline', goOffline);
return () => {
window.removeEventListener('online', goOnline);
window.removeEventListener('offline', goOffline);
};
}, []);
return isOnline;
}
// Usage in any component:
function StatusBadge() {
const isOnline = useOnlineStatus();
return <span>{isOnline ? 'Online' : 'Offline'}</span>;
}
Żaden z komponentów nie musi już samodzielnie konfigurować słuchaczy zdarzeń — każdy po prostu żąda aktualnej wartości za pomocą useOnlineStatus.
Dzielenie się logiką stanu bez dzielenia się samym stanem
To szczegół, który często zaskakuje nowicjuszy: dostosowany hook dzieli się behawiorem, a nie samym stanem. Jeśli dwa oddzielne komponenty wywołają useOnlineStatus, każdy z nich otrzymuje swoją własną, prywatną kopię tego stanu. Przechodzą przez identyczną logikę, ale rzeczywiste wartości w każdym komponencie są całkowicie niezależne — nie ma między nimi żadnego wspólnego ani powiązanego stanu.
Główne zalety używania dostosowanych hooków w React
- Możliwość ponownego użycia w różnych komponentach: Gdy logika znajduje się w hooku, żaden z komponentów aplikacji nie musi kopiować ani jednej linijki kodu, aby jej użyć, co gwarantuje spójne zachowanie w każdym miejscu jej zastosowania.
- Czystsze, łatwiejsze do odczytania komponenty: Wyjęcie logiki związanej ze stanem poza komponent oznacza, że pozostały kod jest w dużej mierze wolny od problemów związanych z zarządzaniem stanem, co znacznie przyspiesza zrozumienie go przez osoby nowe.
- Latwiejsze testowanie w izolacji: Wyodrębnioną logikę można testować całkowicie oddzielnie od dowolnego komponentu, który ją wykorzystuje, co oznacza, że wystarczy ją sprawdzić tylko raz, zamiast ponownie testować ją pośrednio za każdym razem, gdy zmienia się komponent, który ją używa.
use — wymaga rzeczywistej biegłości w podstawowych wzorcach Reacta. Zespoły, które chcą, aby ta kwestia była rozwiązana prawidłowo od samego początku, czasami szukają pomocy poza swoimi pracownikami i angażują dedykowanych programistów ReactJS, specjalistów, których doświadczenie pomaga utrzymać solidną strukturę projektu hooki w miarę jego rozwoju.Częste błędy, których należy unikać
Nawet hooki napisane z dobrymi intencjami mogą pójść nie tak na kilka przewidywalnych sposobów.
- Naruszanie zasad hooków: Wywoływanie hooka wewnątrz warunku, w pętli lub z zwykłej funkcji zamiast z komponentu lub innego hooka zakłóca zdolność React do utrzymywania spójności stanu podczas każdego renderowania. Skutkiem jest zazwyczaj dziwny, przerywany błąd, którego przyczynę trudno ustalić.
- Zbyt duża ilość funkcji w jednym hooku: Umieszczanie walidacji formularzy, żądań sieciowych oraz zarządzania stanem interfejsu w jednym dostosowanym hooku utrudnia jego testowanie, ponowne wykorzystanie oraz zrozumienie w porównaniu do sytuacji, gdy te same zadania są rozdzielone między dwa lub trzy mniejsze, bardziej specjalistyczne hooki.
useState zasługuje na to, by stać się osobnym hookiem. Jeśli jakaś logika jest używana tylko w jednym miejscu, jej wyodrębnienie dodaje jedynie dodatkową warstwę pośrednictwa bez żadnej rzeczywistej korzyści.Wniosek
Haki dostosowane w React nie tylko pomagają unikać powtarzania kodu, ale stanowią również rzeczywisty mechanizm utrzymywania spójności i konsekwencji w coraz większej bazie kodu. Gdy zespół nabywa umiejętności rozpoznawania logiki, którą warto wyodrębnić, komponenty zazwyczaj stają się mniej skomplikowane, błędy łatwiej jest wykryć, a zachowanie aplikacji pozostaje jednolite, zamiast stopniowo różnić się pomiędzy komponentami, które miały działać w ten sam sposób. W miarę jak aplikacje React rosną pod względem skali i złożoności, rozumienie, kiedy i jak stworzyć solidny hak dostosowany, staje się podstawową umiejętnością, a nie czymś przeznaczonym wyłącznie dla zaawansowanych programistów.
Jeśli wasz zespół zmaga się z bazą kodu pełną powtarzającej się logiki i chce nadać jej prawdziwą strukturę, warto skonsultować się z firmą zajmującą się rozwojem w React JS, która już przeprowadzała podobne przeróbki na innych projektach dużego rozmiaru.
Powiązane artykuły
- Typowanie w React Hooks: useState, useEffect, useReducer i niestandardowe hooki — Dowiedz się, jak prawidłowo typować useState, useEffect, useReducer oraz niestandardowe hooki w TypeScript, a także kiedy wybór TypeScript zamiast zwykłego JavaScripta faktycznie się opłaca.