0Pricing
React Academy · Lekcja

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 writes

React 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

  1. Pomiar Core Web Vitals w aplikacjach React
  2. Analiza bundle'a i strategia dzielenia kodu
  3. Optymalizacja obrazów i fontów w React
  4. Zmniejszanie INP: optymalizacja handlerów zdarzeń
← Powrót do React Academy