Zmniejszanie INP: optymalizacja handlerów zdarzeń
Ograniczanie częstotliwości ciężkich handlerów, używanie scheduler.yield() i unikanie długich zadań blokujących główny wątek.
Zmniejszanie INP: optymalizacja handlerów zdarzeń to bezpłatna lekcja React Academy na CoddyKit. To lekcja 4 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.
Czym jest INP?
Interaction to Next Paint (INP) mierzy opóźnienie od interakcji użytkownika (kliknięcia, dotknięcia lub naciśnięcia klawisza) do momentu, gdy przeglądarka wyrenderuje odpowiedź. INP > 200ms sprawia wrażenie ociężałości.
Dlaczego zdarzenia React mogą działać wolno
Procedury obsługi zdarzeń React, które wykonują zbyt dużo pracy synchronicznie, blokują główny wątek. Przeglądarka nie może wyrenderować odpowiedzi, dopóki zadanie JS się nie zakończy — powoduje to wysoki wynik INP.
Debouncing wpisywanego tekstu
Należy stosować debouncing dla kosztownych operacji (wywołań API wyszukiwania i intensywnych obliczeń) uruchamianych podczas naciskania klawiszy. Aktualizacje stanu React przy każdym naciśnięciu klawisza są w porządku; debouncing należy zastosować do kosztownej pracy.
import { useDeferredValue, useState } from 'react';
function SearchPage() {
const [query, setQuery] = useState('');
const deferredQuery = useDeferredValue(query); // defers re-render of slow parts
return (
<>
<input value={query} onChange={e => setQuery(e.target.value)} />
<SearchResults query={deferredQuery} /> {/* re-renders with lower priority */}
</>
);
}useTransition dla niepilnych aktualizacji
Należy opakować wolne aktualizacje stanu w startTransition, aby oznaczyć je jako niepilne. React odroczy ich wykonanie, zachowując responsywność pola tekstowego.
const [isPending, startTransition] = useTransition();
function handleFilter(value) {
setInputValue(value); // urgent — update input immediately
startTransition(() => {
setFilteredList(expensiveFilter(value)); // non-urgent — can be interrupted
});
}Przenoszenie ciężkich operacji poza główny wątek
Do zadań intensywnie wykorzystujących procesor (parsowania dużych zbiorów danych i przetwarzania obrazów) należy używać Web Workers. Główny wątek pozostaje responsywny, podczas gdy worker wykonuje obliczenia.
const worker = new Worker(new URL('./heavy-worker.js', import.meta.url));
function processData(data) {
return new Promise(resolve => {
worker.postMessage(data);
worker.onmessage = e => resolve(e.data);
});
}
// In component:
const handleClick = async () => {
const result = await processData(largeDataset); // doesn't block main thread
setResult(result);
};Unikanie długich zadań
Długie zadania (>50ms) blokują główny wątek i zwiększają wynik INP. Należy dzielić je za pomocą setTimeout, scheduler.yield() lub requestIdleCallback.
async function processInChunks(items) {
const CHUNK_SIZE = 100;
for (let i = 0; i < items.length; i += CHUNK_SIZE) {
const chunk = items.slice(i, i + CHUNK_SIZE);
processChunk(chunk);
await new Promise(r => setTimeout(r, 0)); // yield to browser between chunks
}
}scheduler.yield() (nowoczesne API)
scheduler.yield() przekazuje sterowanie z powrotem do pętli zdarzeń przeglądarki, umożliwiając przetworzenie oczekujących interakcji użytkownika przed wznowieniem kodu.
async function longTask() {
for (const item of largeList) {
processItem(item);
if (/* every N items */) {
await scheduler.yield(); // let browser handle pending clicks/inputs
}
}
}Unikanie synchronicznego układu w procedurach obsługi
Odczytywanie właściwości układu (offsetWidth, getBoundingClientRect()) wymusza synchroniczne ponowne przeliczenie układu. Należy grupować odczyty przed zapisami, aby uniknąć nadmiernych przeliczeń układu.
// Bad — forces layout recalculation on each iteration:
items.forEach(item => {
const height = item.offsetHeight; // READ — forces layout
item.style.height = height * 2 + 'px'; // WRITE — dirties layout
});
// Good — batch reads, then writes:
const heights = items.map(item => item.offsetHeight); // all reads
heights.forEach((h, i) => items[i].style.height = h * 2 + 'px'); // all writesReact 19 Actions dla asynchronicznego INP
React 19 Actions obsługują asynchroniczne mutacje bez blokowania interfejsu — aktualizacje stanu oczekiwania przebiegają niezależnie, dzięki czemu strona pozostaje interaktywna.
function LikeButton({ postId }) {
const [optimistic, setOptimistic] = useOptimistic(false);
async function handleLike() {
setOptimistic(true);
await likePost(postId); // async — doesn't block
}
return <button onClick={handleLike}>{optimistic ? 'Liked' : 'Like'}</button>;
}Pułapki delegowania zdarzeń
React używa delegowania zdarzeń syntetycznych (dołącza jeden listener do elementu głównego). Należy unikać dołączania setek indywidualnych listenerów DOM w useEffect — zamiast tego należy używać zdarzeń syntetycznych React na elementach JSX.
Mierzenie INP w DevTools
Należy użyć panelu Performance w Chrome DevTools, aby zarejestrować interakcję i przeanalizować długie zadania. Na osi czasu należy szukać wpisów „Interaction” i rozwinąć je, aby znaleźć blokujące wykonania skryptów.
Szybki sprawdzian
Który hook React oznacza aktualizację stanu jako niepilną, dzięki czemu może ona zostać przerwana przez interakcje użytkownika?
Podsumowanie
Aby zmniejszyć INP, należy stosować debouncing kosztownej pracy, używać startTransition dla niepilnych aktualizacji, przenosić zadania obciążające procesor do Web Workers oraz dzielić długie zadania za pomocą scheduler.yield(). Odczyty DOM należy grupować przed zapisami, aby uniknąć nadmiernych przeliczeń układu.
Często zadawane pytania
Czy lekcja „Zmniejszanie INP: optymalizacja handlerów zdarzeń” jest bezpłatna?
Tak — pełny tekst „Zmniejszanie INP: optymalizacja handlerów zdarzeń” 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 „Zmniejszanie INP: optymalizacja handlerów zdarzeń”?
Ograniczanie częstotliwości ciężkich handlerów, używanie scheduler.yield() i unikanie długich zadań blokujących główny wątek. Ć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 4 z 4.
Ile czasu zajmuje lekcja „Zmniejszanie INP: optymalizacja handlerów zdarzeń”?
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
- Pomiar Core Web Vitals w aplikacjach React
- Analiza bundle'a i strategia dzielenia kodu
- Optymalizacja obrazów i fontów w React
- Zmniejszanie INP: optymalizacja handlerów zdarzeń