useMemo i useCallback na potrzeby wydajności
Proszę zapamiętywać kosztowne obliczenia za pomocą useMemo oraz stabilne referencje funkcji za pomocą useCallback, aby zapobiegać niepotrzebnemu ponownemu renderowaniu komponentów potomnych.
useMemo i useCallback na potrzeby wydajności to bezpłatna lekcja Frontend 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 Frontend Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Frontend Academy zawiera 4 lekcji w sumie.
Domyślne zachowanie Reacta
Domyślnie React ponownie renderuje komponent za każdym razem, gdy zmienia się jego stan lub ponownie renderuje się jego rodzic. Komponenty potomne również są ponownie renderowane, nawet jeśli ich propsy się nie zmieniły. W przypadku większości komponentów jest to w porządku — React jest szybki.
useMemo — memoizowanie kosztownych wartości
useMemo(fn, deps) buforuje wynik obliczeń. Funkcja jest wykonywana tylko wtedy, gdy zmienią się zależności. Należy używać useMemo w przypadku kosztownych obliczeń, których powtarzanie przy każdym renderowaniu byłoby niepotrzebne.
const expensiveResult = useMemo(() => {
return items.filter(item => item.category === category).sort((a, b) => a.price - b.price);
}, [items, category]);
// Only recalculates when items or category changesuseCallback — memoizowanie funkcji
useCallback(fn, deps) zwraca memoizowaną funkcję, która zachowuje tę samą referencję, dopóki nie zmienią się zależności. Należy używać useCallback podczas przekazywania funkcji zwrotnych do głęboko zagnieżdżonych lub memoizowanych komponentów.
const handleDelete = useCallback((id: string) => {
setItems(prev => prev.filter(item => item.id !== id));
}, []); // stable reference — empty deps because only setItems is used
<ItemList items={items} onDelete={handleDelete} />React.memo — pomijanie ponownego renderowania
React.memo(Component) opakowuje komponent, dzięki czemu jest on ponownie renderowany tylko wtedy, gdy zmienią się jego propsy (porównanie płytkie). Należy połączyć React.memo z useCallback, aby propsy zawierające funkcje zwrotne miały stabilne referencje.
const MemoItem = React.memo(function Item({ text, onDelete }: ItemProps) {
console.log('Item rendered:', text); // only logs when props change
return <li>{text} <button onClick={onDelete}>×</button></li>;
});
// onDelete must be stable (from useCallback) for memo to helpKiedy NIE optymalizować
Przedwczesna optymalizacja jest pułapką. useMemo i useCallback mają swój koszt: domknięcie oraz porównywanie zależności. W przypadku tanich operacji (na przykład filtrowania 10 elementów) narzut przewyższa korzyści. Należy optymalizować dopiero po zmierzeniu rzeczywistego problemu z wydajnością.
Profilowanie przed optymalizacją
Przed dodaniem memoizacji należy użyć profilera React DevTools do zmierzenia rzeczywistych czasów renderowania. Profiler pokazuje, które komponenty zajmują najwięcej czasu i ile razy są renderowane. Należy wprowadzać poprawki na podstawie danych, a nie założeń.
useMemo do stabilizowania referencji
useMemo jest również przydatne do utrzymywania stabilnej referencji — nie ze względu na wydajność samych obliczeń, lecz aby zapobiec niepotrzebnemu ponownemu uruchamianiu podrzędnej memoizacji lub efektu.
// Without useMemo, this creates a new array every render:
const config = useMemo(() => ({ endpoint: '/api', timeout: 5000 }), []);
// Without memoization, useEffect would re-run on every render:
useEffect(() => { initSDK(config); }, [config]);Zależności useCallback
useCallback podlega tym samym zasadom dotyczącym zależności co useEffect. Należy uwzględnić każdą zmienną z zewnętrznego zakresu, której używa funkcja zwrotna. Settery stanu (z useState) są zawsze stabilne i nie trzeba umieszczać ich w deps.
Zależność między useMemo i useCallback
useCallback(fn, deps) jest równoważne useMemo(() => fn, deps). Oba hooki korzystają z tego samego mechanizmu — useCallback to po prostu skrócona składnia memoizowania funkcji.
Memoizacja elementów listy
Typowy wzorzec polega na memoizowaniu komponentów elementów listy, gdy lista jest duża i często ponownie renderowana. Należy przekazywać stabilne funkcje zwrotne z useCallback, aby nie niweczyć działania memoizacji.
const MemoRow = React.memo(Row);
const handleEdit = useCallback((id) => edit(id), []);
const handleDel = useCallback((id) => remove(id), []);
{rows.map(row => (
<MemoRow key={row.id} row={row} onEdit={handleEdit} onDelete={handleDel} />
))}Memoizacja wartości kontekstu
Należy memoizować wartość przekazywaną do komponentu Provider kontekstu, aby zapobiec ponownemu renderowaniu wszystkich komponentów korzystających z kontekstu za każdym razem, gdy ponownie renderuje się rodzic komponentu Provider.
const value = useMemo(() => ({ user, login, logout }), [user]);Szybki test
Jaki jest cel użycia useCallback?
Podsumowanie: useMemo i useCallback
useMemo buforuje kosztowne obliczone wartości. useCallback buforuje referencje funkcji. React.memo pomija ponowne renderowanie, gdy propsy nie zmieniają się w porównaniu płytkim. Wszystkie trzy mechanizmy można łączyć, aby poprawić wydajność komponentów. Najpierw należy profilować — przedwczesna memoizacja zwiększa złożoność bez korzyści. Stabilne referencje zapobiegają niepotrzebnemu ponownemu uruchamianiu podrzędnych efektów i mechanizmów memoizacji.
Często zadawane pytania
Czy lekcja „useMemo i useCallback na potrzeby wydajności” jest bezpłatna?
Tak — pełny tekst „useMemo i useCallback na potrzeby wydajności” 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 Frontend Academy, przejdź na CoddyKit PRO. Kurs Frontend Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „useMemo i useCallback na potrzeby wydajności”?
Proszę zapamiętywać kosztowne obliczenia za pomocą useMemo oraz stabilne referencje funkcji za pomocą useCallback, aby zapobiegać niepotrzebnemu ponownemu renderowaniu komponentów potomnych. Ćwiczysz Frontend 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ąć Frontend Academy?
Nie wymagamy żadnego doświadczenia. Frontend 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 „useMemo i useCallback na potrzeby wydajności”?
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 Frontend Academy?
Tak. Każda lekcja Frontend 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
- useContext do stanu globalnego
- useReducer do złożonego stanu
- useMemo i useCallback na potrzeby wydajności
- Własne hooki: wydzielanie wielokrotnego użytku logiki