Implementowanie własnego hooka useThrottle
Budować hook useThrottle ograniczający częstotliwość aktualizacji wartości podczas szybkich zdarzeń, takich jak przewijanie
Implementowanie własnego hooka useThrottle to bezpłatna lekcja React Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej React Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs React Academy zawiera 4 lekcji w sumie.
Throttle jest trudniejszy niż debounce
Debounce po prostu resetuje timer przy każdym zdarzeniu. Throttle musi aktywnie śledzić, kiedy nastąpiło ostatnie wykonanie, i ustalać, czy upłynęło wystarczająco dużo czasu, aby wykonać funkcję ponownie. Wymaga to zachowania znacznika czasu między renderowaniami, dlatego implementacja jest nieco bardziej złożona niż w przypadku debounce.
Używanie useRef dla lastRunTime
Znacznik czasu ostatniego wykonania musi być zachowywany między renderowaniami bez wywoływania ponownych renderowań, dlatego właściwym narzędziem jest useRef. Należy przechowywać znacznik czasu jako const lastRunTime = useRef(Date.now()). W przeciwieństwie do stanu aktualizacja refa nie powoduje ponownego renderowania, więc logika throttle działa wydajnie, bez dodatkowych cykli.
Sygnatura hooka
Hook useThrottle(value, delay) zwraca wersję wartości wejściowej przetwarzaną za pomocą throttle. Jego kontrakt jest podobny do useDebounce: przyjmuje dowolną wartość i opóźnienie w ms, a zwraca wartość objętą throttle. Komponenty używają go w taki sam sposób, dzięki czemu może on być bezpośrednim zamiennikiem w przypadku innych zasad określania czasu.
Implementacja trailing edge
Throttle typu trailing edge aktualizuje wartość na końcu każdego interwału. Gdy nadejdzie nowa wartość, należy zaplanować setTimeout na czas pozostały do końca interwału: delay - (Date.now() - lastRunTime.current). Gdy timer się uruchomi, należy zaktualizować stan i zapisać nową wartość lastRunTime. W funkcji cleanup należy anulować poprzednie timery.
Implementacja leading edge
Throttle typu leading edge natychmiast stosuje pierwszą wartość, a kolejne ignoruje do wygaśnięcia interwału. Należy sprawdzić, czy Date.now() - lastRunTime.current >= delay, a następnie zaktualizować stan i zapisać czas. W przeciwnym razie aktualizację należy pominąć. Zapewnia to natychmiastową reakcję na pierwsze działanie oraz następujący po nim okres oczekiwania.
Połączenie leading edge i trailing edge
Najlepszy UX często łączy oba podejścia: natychmiastową reakcję na pierwsze zdarzenie (leading), a następnie zastosowanie końcowego stanu po upływie interwału (trailing). Dzięki temu użytkownik widzi szybką początkową reakcję, a końcowa wartość zawsze zostaje zastosowana po zakończeniu ruchu, co zapobiega pozostawieniu nieaktualnego stanu końcowego.
Użycie useRef do przechowywania identyfikatora timeoutu
Oczekujący identyfikator timeoutu należy przechowywać w useRef: const timeoutRef = useRef(null). Przed zaplanowaniem nowego timeoutu należy wywołać clearTimeout(timeoutRef.current), aby anulować istniejący. Zapobiega to nakładaniu się wielu timerów, które powodowałyby wielokrotne aktualizacje w ramach jednego interwału throttle.
Czyszczenie przy odmontowaniu komponentu
Funkcja cleanup w useEffect powinna wywoływać clearTimeout(timeoutRef.current), aby anulować oczekującą aktualizację trailing podczas odmontowywania komponentu. Bez tego oczekujący timeout uruchomi się po odmontowaniu i spróbuje ustawić stan w odmontowanym komponencie, co może powodować ostrzeżenia Reacta.
Alternatywa w postaci throttlowanego callbacku
Zamiast hooka opartego na wartości można utworzyć hook throttle oparty na useCallback: useThrottledCallback(fn, delay) zwraca throttlowaną wersję funkcji. Jest to bardziej elastyczne rozwiązanie, gdy throttlowana operacja jest wywołaniem funkcji, na przykład trackera analitycznego, a nie wartością reaktywną.
Testowanie throttle za pomocą fałszywych timerów
W testach Jest należy użyć jest.useFakeTimers(), aby kontrolować czas. Należy skonfigurować throttle z opóźnieniem 1000 ms, wywołać 10 szybkich zmian wartości, następnie przesunąć fałszywy czas o 500 ms i sprawdzić, czy nastąpiła tylko 1 lub 2 aktualizacje. Po przesunięciu czasu o kolejne 500 ms należy zweryfikować, czy uruchomiła się aktualizacja trailing. Pozwala to deterministycznie sprawdzić działanie throttle.
Throttle w modelu Reacta
React przetwarza aktualizacje stanu partiami podczas renderowania. Throttle działający na aktualizacjach stanu dobrze współpracuje z tym modelem. Należy jednak pamiętać, że w React 18 Concurrent Mode renderowanie może zostać przerwane. Sama logika throttle, oparta na rzeczywistym czasie zegarowym za pośrednictwem Date.now(), nie zależy od sposobu planowania renderowania przez React.
Throttle trailing a leading edge
Na której krawędzi uruchamia się throttle typu „trailing”?
Podsumowanie lekcji: hook useThrottle
Throttle wymaga śledzenia czasu ostatniego wykonania za pomocą useRef. Hook może implementować leading edge (natychmiastowe wykonanie), trailing edge (odroczone wykonanie) albo oba podejścia. Identyfikator timeoutu należy zawsze przechowywać w refie i anulować go w funkcji cleanup. W przypadkach opartych na funkcjach warto użyć wzorca useThrottledCallback. Dla niezawodności należy przeprowadzać testy z użyciem fałszywych timerów.
Często zadawane pytania
Czy lekcja „Implementowanie własnego hooka useThrottle” jest bezpłatna?
Tak — pełny tekst „Implementowanie własnego hooka useThrottle” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu React Academy, przejdź na CoddyKit PRO. Kurs React Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Implementowanie własnego hooka useThrottle”?
Budować hook useThrottle ograniczający częstotliwość aktualizacji wartości podczas szybkich zdarzeń, takich jak przewijanie Ćwiczysz React Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć React Academy?
Nie wymagamy żadnego doświadczenia. React Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.
Ile czasu zajmuje lekcja „Implementowanie własnego hooka useThrottle”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji React Academy?
Tak. Każda lekcja React Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Dlaczego debounce i throttle są ważne w interfejsach
- Implementowanie własnego hooka useDebounce
- Implementowanie własnego hooka useThrottle
- Zastosowania praktyczne: wyszukiwanie, przewijanie, zmiana rozmiaru