Skip to content

09. Optymalizacja wydajności React

This content is not available in your language yet.

Optymalizacja wydajności React

React renderuje komponenty za każdym razem gdy zmienia się ich stan lub props. React.memo zapobiega re-renderom gdy props się nie zmieniły. useCallback memoizuje funkcje, useMemo memoizuje kosztowne obliczenia. Ale: przedwczesna optymalizacja jest złem — używaj tylko gdy mierzysz problem.

  1. Kiedy React re-renderuje? — Zmiana state, zmiana props, re-render rodzica
  2. Co to jest memoizacja? — Zapamiętanie wyniku dla tych samych argumentów
  3. React.memo vs useMemo? — memo dla komponentów, useMemo dla wartości
  4. Kiedy NIE używać? — Małe komponenty, rzadko zmieniające się dane — overhead kosztu
  1. Problem zbędnych re-renderów — dlaczego każda zmiana stanu rodzica re-renderuje dziecko
  2. React.memo — HOC owijający komponent, shallow comparison props
  3. useCallback — memoizacja funkcji przekazywanych jako props
  4. useMemo — memoizacja kosztownych obliczeń (filtrowanie, sortowanie dużych list)
  5. Zasada — mierz (Profiler), a potem optymalizuj

Schemat

Drzewo komponentów: rodzic ma stan A i B. Dziecko używa tylko A. Bez memo: zmiana B re-renderuje dziecko. Z memo: zmiana B NIE re-renderuje dziecka — React porównuje props.

Przykład kodu JSX

Lista produktów z filtrem — bez i z useMemo na filtrowanej liście + ekspensywne obliczenie ceny.

  • Kiedy React re-renderuje (diagram)
  • React.memo z prostym przykładem
  • Kiedy NIE optymalizować

Forma: 10 slajdów, 10 minut

Ocena: 3.0
// Bez memo: każdy re-render rodzica = re-render ProductCard
// Nawet gdy product się nie zmienił!
function ProductCard({ product }) {
console.log('Render ProductCard:', product.id);
return <div>{product.name}{product.price}</div>;
}
// Z memo: re-render tylko gdy props product się zmieni
const ProductCard = React.memo(function ProductCard({ product }) {
console.log('Render ProductCard:', product.id);
return <div>{product.name}{product.price}</div>;
});
function ProductList({ products, searchTerm }) {
// Bez useMemo: filtrowanie 10000 produktów przy każdym re-renderze
// Z useMemo: filtrowanie tylko gdy products lub searchTerm się zmieni
const filteredProducts = useMemo(
() => products.filter(p =>
p.name.toLowerCase().includes(searchTerm.toLowerCase())
),
[products, searchTerm]
);
return (
<ul>
{filteredProducts.map(p => <li key={p.id}>{p.name}</li>)}
</ul>
);
}
// Problem: nowa funkcja = nowe referencja = re-render dziecka mimo memo
function Parent() {
const [count, setCount] = useState(0);
// Bez useCallback: nowa funkcja przy każdym renderze rodzica
// Z useCallback: ta sama referencja (chyba że count się zmieni)
const handleDelete = useCallback((id) => {
// logika usuwania
console.log('Usuwam:', id);
}, []); // puste deps = zawsze ta sama funkcja
return <Child onDelete={handleDelete} />;
}
const Child = React.memo(function Child({ onDelete }) {
// Dzięki memo + useCallback — re-render tylko gdy onDelete się zmieni
return <button onClick={() => onDelete(1)}>Usuń</button>;
});

Mierz, nie zgaduj!

Podkreślcie: NIGDY nie optymalizujcie bez dowodów z profilera. Dodawanie memo wszędzie spowalnia aplikację przez overhead porównań props!

Pokaż Profiler

Otwórzcie React DevTools → Profiler → nagrajcie kilka kliknięć. Pokaż klasie flamegraph z kolorowymi komponentami — red = długi render.

Szybkie aplikacje to happy użytkownicy!

Optymalizacja to wyższy poziom React. Po tej prezentacji klasa będzie wiedziała jak identyfikować i naprawiać bottlenecki wydajnościowe!