Kaskada ponownych renderów React: gdy jedno kliknięcie renderuje całe drzewo
Co się dzieje
W React aktualizacja stanu renderuje ponownie komponent i domyślnie wszystkie jego dzieci. Jeśli stan żyje wysoko w drzewie (kontekst, store na poziomie strony), pojedyncze naciśnięcie klawisza lub kliknięcie może ponownie wyrenderować setki komponentów — z których większość pokazuje dokładnie to samo co wcześniej.
Pojedynczy render jest tani; tysiące w jednej obsłudze już nie. Praca trafia do fazy processing time INP.
Jak rozpoznać
- Profiler React DevTools pokazuje szerokie wykresy płomieniowe: komponenty renderują się ponownie bez widocznej zmiany ich propsów.
- Pisanie w kontrolowanym input zacina się; każde naciśnięcie klawisza renderuje ponownie duże listy lub tabele.
- Processing time dominuje w INP, a stos w DevTools Performance jest pełen wewnętrznych elementów React.
Jak naprawić
- Przesuń stan w dół: trzymaj go w najmniejszym komponencie, który go potrzebuje, zamiast w komponencie na poziomie strony lub w kontekście.
- Owiń kosztowne poddrzewa w React.memo i ustabilizuj przekazywane im propsy za pomocą useCallback/useMemo — memo jest bezużyteczne, jeśli przy każdym renderze tworzony jest nowy callback.
- Oznacz niepilne aktualizacje (filtrowanie listy podczas pisania) za pomocą useTransition, aby pilny render (sam input) został narysowany najpierw.
Problem
const Page = () => {
const [query, setQuery] = useState("")
// every keystroke re-renders Page → Header, Sidebar, BigTable, Footer
return <>
<SearchInput value={query} onChange={setQuery} />
<BigTable rows={filterRows(rows, query)} />
</>
}
Poprawka
const BigTable = React.memo(({ rows }) => /* ... */)
const Page = () => {
const [query, setQuery] = useState("")
const [isPending, startTransition] = useTransition()
const rows = useMemo(() => filterRows(allRows, query), [query])
const onChange = (q) =>
startTransition(() => setQuery(q)) // input paints first, table follows
return <>
<SearchInput onChange={onChange} />
<BigTable rows={rows} />
</>
}
Przeskanuj swoją stronę za darmo →