Własny hook to funkcja, której nazwa zaczyna się od use i która wywołuje inne hooki. Piszesz go, gdy dwa komponenty potrzebują tej samej logiki ze stanem: przenieś wywołania useState i useEffect do funkcji, zwróć to, czego potrzebuje komponent, i wywołaj ją z każdego komponentu.
Oba spoilery wywołują useToggle, a otwarcie jednego zostawia drugi zamknięty. Każde wywołanie wykonuje własne useState, więc każdy komponent dostaje własną wartość. Własny hook współdzieli logikę, a nie stan.
Zasady pisania własnego hooka
- Nazwa zaczyna się od
usei wielkiej litery:useToggle,useOnlineStatus. Reguła lintera dla hooków używa tego przedrostka, żeby znaleźć wywołania hooków i je sprawdzić. - Wywołuje co najmniej jeden hook. Pomocnik, który nie wywołuje żadnych hooków, to zwykła funkcja; nazwij go
formatDate, a nieuseFormatDate, żeby dało się go wywołać wszędzie, także w warunkach. - Przestrzega zasad hooków: wywołuje hooki na swoim najwyższym poziomie i jest wywoływany tylko z komponentów albo innych własnych hooków.
- Zwraca to, co jest przydatne. Tablica (
[on, toggle]) jest wygodna, gdy wywołujący zmieniają nazwy wartości; obiekt ({ data, loading, error }) czyta się lepiej przy trzech wartościach i więcej.
useLocalStorage: stan, który przetrwa przeładowanie
useState zapomina wszystko po przeładowaniu. Ten hook odczytuje wartość początkową z localStorage i zapisuje tam każdą zmianę.
Podgląd działa w odizolowanej ramce, w której przeglądarka blokuje localStorage, więc tutaj zobaczysz ostrzeżenie w konsoli, a hook wróci do zwykłego stanu. Na normalnej stronie imię przetrwa przeładowanie. try/catch nie jest tylko dla tego podglądu: tryby prywatne, zablokowane ciasteczka i pełny limit miejsca sprawiają, że magazyn rzuca błędy także w prawdziwych aplikacjach. Przekazanie funkcji do useState oznacza, że magazyn jest odczytywany raz, przy pierwszym renderowaniu.
useDebounce: poczekaj, aż użytkownik przestanie pisać
Pole wyszukiwania nie powinno wysyłać żądania przy każdym naciśnięciu klawisza. useDebounce zwraca kopię wartości, która aktualizuje się dopiero wtedy, gdy wartość przestanie się zmieniać przez zadany czas.
Szybko wpisz słowo: Typed podąża za każdym klawiszem, Debounced dogania pół sekundy po tym, jak przestaniesz, a konsola wypisuje jedno wyszukiwanie. Każde naciśnięcie klawisza zmienia value, więc React uruchamia funkcję czyszczącą (clearTimeout), zanim wystartuje nowy timer. Zmień 500 na 0, a każde naciśnięcie klawisza wypisze własne wyszukiwanie.
useWindowWidth: subskrypcja z funkcją czyszczącą
Hook, który nasłuchuje przeglądarki, musi usunąć nasłuchiwanie, gdy komponent znika, bo inaczej każde zamontowanie je zostawia.
Zmień rozmiar okna przeglądarki, a liczba za nim podąży. Kliknij przycisk, a konsola pokaże usunięcie nasłuchiwania. Usuń return z efektu, a potem kilka razy zamontuj i odmontuj komponent: za każdym razem dostajesz linię added, a żadnej removed, więc stare nasłuchiwania się kumulują. Dla wartości przeglądarki takich jak ta useSyncExternalStore to hook, który React zbudował właśnie do tego zadania, i warto wywoływać go wewnątrz własnego hooka.
Logika jest współdzielona, stan nie
Dwa komponenty wywołujące ten sam hook dostają dwie osobne kopie wszystkiego, co jest w środku. Zaskakuje to osoby, które oczekują, że hook zadziała jak zmienna globalna.
Kliknij którykolwiek przycisk, a ruszy się tylko ten licznik. Jeśli oba mają pokazywać tę samą liczbę, przenieś stan do App i przekaż go w dół albo umieść go w kontekście. Własny hook może dla wygody opakować taki wspólny stan (useCart() czytający CartContext), ale współdzielenie wynika z kontekstu, a nie z hooka.
Kiedy pisać własny hook
Wydziel hook, gdy ta sama grupa wywołań hooków pojawia się w dwóch komponentach albo gdy logika efektu w jednym komponencie jest na tyle długa, że nazwa wyjaśniłaby ją lepiej (useOnlineStatus() czyta się lepiej niż dwadzieścia linii nasłuchiwania). Nie opakowuj pojedynczego wywołania useState w hook tylko po to, żeby zmienić mu nazwę, i nie pisz hooków, które tylko wywołują useEffect, żeby ustawić stan z propsów; zamiast tego wyliczaj tę wartość podczas renderowania.
Najczęściej zadawane pytania
Co to jest własny hook w React?
Funkcja JavaScript, której nazwa zaczyna się od use i która wywołuje jeden albo więcej innych hooków. Pakuje logikę ze stanem (stan, efekty, refy), żeby każdy komponent mógł jej użyć, wywołując tę funkcję.
Czy własne hooki współdzielą stan między komponentami?
Nie. Każde wywołanie własnego hooka wykonuje własne wywołania useState i useEffect, więc każdy komponent dostaje niezależny stan. Żeby współdzielić tę samą wartość między komponentami, podnieś stan albo umieść go w kontekście lub zewnętrznym magazynie danych.
Dlaczego nazwa własnego hooka musi zaczynać się od use?
Nazwa mówi regułom lintera Reacta i innym programistom, że funkcja wywołuje hooki, więc obowiązują ją zasady hooków: wywołuj ją na najwyższym poziomie, nigdy w warunku ani pętli. Bez tego przedrostka linter nie może sprawdzić wywołań w środku.
Czy własny hook może zwracać JSX?
Może zwracać cokolwiek, ale jeśli zwraca JSX, zwykle lepiej napisać go jako komponent. Własne hooki zwykle zwracają wartości i funkcje, jako tablicę ([value, toggle]) albo obiekt ({ data, error, loading }).
Czy mogę wywołać własny hook wewnątrz useEffect albo handlera zdarzenia?
Nie. Własny hook to wciąż hook, więc przestrzega zasad hooków: wywołuj go na najwyższym poziomie komponentu albo innego własnego hooka.