Polski

Kompleksowy przewodnik po optymalizacji wydajności aplikacji React przy użyciu useMemo, useCallback i React.memo. Naucz się zapobiegać niepotrzebnym ponownym renderowaniom i poprawiać doświadczenie użytkownika.

Optymalizacja Wydajności React: Mistrzowskie Użycie useMemo, useCallback i React.memo

React, popularna biblioteka JavaScript do budowania interfejsów użytkownika, znana jest ze swojej architektury opartej na komponentach i deklaratywnego stylu. Jednak w miarę wzrostu złożoności aplikacji, wydajność może stać się problemem. Niepotrzebne ponowne renderowania komponentów mogą prowadzić do powolnego działania i słabego doświadczenia użytkownika. Na szczęście React udostępnia kilka narzędzi do optymalizacji wydajności, w tym useMemo, useCallback i React.memo. Ten przewodnik zagłębia się w te techniki, dostarczając praktycznych przykładów i użytecznych spostrzeżeń, które pomogą Ci budować wydajne aplikacje React.

Zrozumienie Ponownych Renderowań w React

Zanim przejdziemy do technik optymalizacji, kluczowe jest zrozumienie, dlaczego w React dochodzi do ponownych renderowań. Kiedy stan lub propsy komponentu ulegają zmianie, React inicjuje ponowne renderowanie tego komponentu, a potencjalnie także jego komponentów potomnych. React używa wirtualnego DOM do efektywnego aktualizowania rzeczywistego DOM, ale nadmierne ponowne renderowania nadal mogą wpływać na wydajność, zwłaszcza w złożonych aplikacjach. Wyobraź sobie globalną platformę e-commerce, na której ceny produktów często się aktualizują. Bez optymalizacji, nawet niewielka zmiana ceny może spowodować ponowne renderowanie całej listy produktów, wpływając na przeglądanie przez użytkownika.

Dlaczego Komponenty Ponownie Się Renderują

Celem optymalizacji wydajności jest zapobieganie niepotrzebnym ponownym renderowaniom, zapewniając, że komponenty aktualizują się tylko wtedy, gdy ich dane faktycznie uległy zmianie. Rozważ scenariusz obejmujący wizualizację danych w czasie rzeczywistym dla analizy rynku akcji. Jeśli komponenty wykresów będą niepotrzebnie renderować się przy każdej drobnej aktualizacji danych, aplikacja stanie się nieresponsywna. Optymalizacja ponownych renderowań zapewni płynne i responsywne doświadczenie użytkownika.

Wprowadzenie do useMemo: Memoizacja Kosztownych Obliczeń

useMemo to hook React, który memoizuje wynik obliczeń. Memoizacja to technika optymalizacyjna, która przechowuje wyniki kosztownych wywołań funkcji i ponownie wykorzystuje te wyniki, gdy pojawią się te same dane wejściowe. Zapobiega to potrzebie niepotrzebnego ponownego wykonywania funkcji.

Kiedy Używać useMemo

Jak Działa useMemo

useMemo przyjmuje dwa argumenty:

  1. Funkcja wykonująca obliczenia.
  2. Tablica zależności.

Funkcja jest wykonywana tylko wtedy, gdy jedna z zależności w tablicy ulegnie zmianie. W przeciwnym razie useMemo zwraca poprzednio zmemoizowaną wartość.

Przykład: Obliczanie Ciągu Fibonacciego

Ciąg Fibonacciego to klasyczny przykład intensywnego obliczeniowo zadania. Stwórzmy komponent, który oblicza n-tą liczbę Fibonacciego przy użyciu useMemo.


import React, { useState, useMemo } from 'react';

function Fibonacci({ n }) {
  const fibonacciNumber = useMemo(() => {
    console.log('Calculating Fibonacci...'); // Demonstrates when the calculation runs
    function calculateFibonacci(num) {
      if (num <= 1) {
        return num;
      }
      return calculateFibonacci(num - 1) + calculateFibonacci(num - 2);
    }
    return calculateFibonacci(n);
  }, [n]);

  return 

Fibonacci({n}) = {fibonacciNumber}

; } function App() { const [number, setNumber] = useState(5); return (
setNumber(parseInt(e.target.value))} />
); } export default App;

W tym przykładzie funkcja calculateFibonacci jest wykonywana tylko wtedy, gdy props n ulega zmianie. Bez useMemo funkcja byłaby wykonywana przy każdym ponownym renderowaniu komponentu Fibonacci, nawet jeśli n pozostałoby takie samo. Wyobraź sobie, że obliczenia te odbywają się na globalnym pulpicie finansowym – każdy tik rynku powoduje pełne przeliczenie, prowadząc do znaczących opóźnień. useMemo temu zapobiega.

Wprowadzenie do useCallback: Memoizacja Funkcji

useCallback to kolejny hook React, który memoizuje funkcje. Zapobiega tworzeniu nowej instancji funkcji przy każdym renderowaniu, co może być szczególnie przydatne przy przekazywaniu funkcji zwrotnych jako propsów do komponentów potomnych.

Kiedy Używać useCallback

Jak Działa useCallback

useCallback przyjmuje dwa argumenty:

  1. Funkcja do zmemoizowania.
  2. Tablica zależności.

Funkcja jest tworzona ponownie tylko wtedy, gdy jedna z zależności w tablicy ulegnie zmianie. W przeciwnym razie useCallback zwraca tę samą instancję funkcji.

Przykład: Obsługa Kliknięcia Przycisku

Stwórzmy komponent z przyciskiem, który wywołuje funkcję zwrotną. Użyjemy useCallback do zmemoizowania funkcji zwrotnej.


import React, { useState, useCallback } from 'react';

function Button({ onClick, children }) {
  console.log('Button re-rendered'); // Demonstrates when the Button re-renders
  return ;
}

const MemoizedButton = React.memo(Button);

function App() {
  const [count, setCount] = useState(0);

  const handleClick = useCallback(() => {
    console.log('Button clicked');
    setCount((prevCount) => prevCount + 1);
  }, []); // Empty dependency array means the function is only created once

  return (
    

Count: {count}

Increment
); } export default App;

W tym przykładzie funkcja handleClick jest tworzona tylko raz, ponieważ tablica zależności jest pusta. Kiedy komponent App jest ponownie renderowany z powodu zmiany stanu count, funkcja handleClick pozostaje taka sama. Komponent MemoizedButton, opakowany w React.memo, będzie ponownie renderowany tylko wtedy, gdy jego propsy ulegną zmianie. Ponieważ prop onClick (handleClick) pozostaje taki sam, komponent Button nie jest niepotrzebnie ponownie renderowany. Wyobraź sobie interaktywną aplikację mapową. Za każdym razem, gdy użytkownik wchodzi w interakcję, dziesiątki komponentów przycisków mogą być dotknięte. Bez useCallback, te przyciski byłyby niepotrzebnie ponownie renderowane, tworząc powolne doświadczenie. Użycie useCallback zapewnia płynniejszą interakcję.

Wprowadzenie do React.memo: Memoizacja Komponentów

React.memo to komponent wyższego rzędu (HOC), który memoizuje komponent funkcyjny. Zapobiega ponownemu renderowaniu komponentu, jeśli jego propsy się nie zmieniły. Jest to podobne do PureComponent dla komponentów klasowych.

Kiedy Używać React.memo

Jak Działa React.memo

React.memo opakowuje komponent funkcyjny i wykonuje płytkie porównanie poprzednich i następnych propsów. Jeśli propsy są takie same, komponent nie zostanie ponownie wyrenderowany.

Przykład: Wyświetlanie Profilu Użytkownika

Stwórzmy komponent, który wyświetla profil użytkownika. Użyjemy React.memo, aby zapobiec niepotrzebnym ponownym renderowaniom, jeśli dane użytkownika się nie zmieniły.


import React from 'react';

function UserProfile({ user }) {
  console.log('UserProfile re-rendered'); // Demonstrates when the component re-renders
  return (
    

Name: {user.name}

Email: {user.email}

); } const MemoizedUserProfile = React.memo(UserProfile, (prevProps, nextProps) => { // Custom comparison function (optional) return prevProps.user.id === nextProps.user.id; // Only re-render if the user ID changes }); function App() { const [user, setUser] = React.useState({ id: 1, name: 'John Doe', email: 'john.doe@example.com', }); const updateUser = () => { setUser({ ...user, name: 'Jane Doe' }); // Changing the name }; return (
); } export default App;

W tym przykładzie komponent MemoizedUserProfile będzie ponownie renderowany tylko wtedy, gdy prop user.id ulegnie zmianie. Nawet jeśli inne właściwości obiektu user ulegną zmianie (np. imię lub email), komponent nie zostanie ponownie wyrenderowany, chyba że ID się zmieni. Ta niestandardowa funkcja porównania w `React.memo` pozwala na precyzyjną kontrolę nad tym, kiedy komponent jest ponownie renderowany. Rozważ platformę mediów społecznościowych z stale aktualizowanymi profilami użytkowników. Bez `React.memo`, zmiana statusu użytkownika lub zdjęcia profilowego spowodowałaby pełne ponowne renderowanie komponentu profilu, nawet jeśli podstawowe dane użytkownika pozostałyby niezmienione. `React.memo` pozwala na ukierunkowane aktualizacje i znacząco poprawia wydajność.

Łączenie useMemo, useCallback i React.memo

Te trzy techniki są najskuteczniejsze, gdy są używane razem. useMemo memoizuje kosztowne obliczenia, useCallback memoizuje funkcje, a React.memo memoizuje komponenty. Łącząc te techniki, można znacznie zmniejszyć liczbę niepotrzebnych ponownych renderowań w aplikacji React.

Przykład: Złożony Komponent

Stwórzmy bardziej złożony komponent, który demonstruje, jak połączyć te techniki.


import React, { useState, useCallback, useMemo } from 'react';

function ListItem({ item, onUpdate, onDelete }) {
  console.log(`ListItem ${item.id} re-rendered`); // Demonstrates when the component re-renders
  return (
    
  • {item.text}
  • ); } const MemoizedListItem = React.memo(ListItem); function List({ items, onUpdate, onDelete }) { console.log('List re-rendered'); // Demonstrates when the component re-renders return (
      {items.map((item) => ( ))}
    ); } const MemoizedList = React.memo(List); function App() { const [items, setItems] = useState([ { id: 1, text: 'Item 1' }, { id: 2, text: 'Item 2' }, { id: 3, text: 'Item 3' }, ]); const handleUpdate = useCallback((id) => { setItems((prevItems) => prevItems.map((item) => item.id === id ? { ...item, text: `Updated ${item.text}` } : item ) ); }, []); const handleDelete = useCallback((id) => { setItems((prevItems) => prevItems.filter((item) => item.id !== id)); }, []); const memoizedItems = useMemo(() => items, [items]); return (
    ); } export default App;

    W tym przykładzie:

    Ta kombinacja technik zapewnia, że komponenty są ponownie renderowane tylko wtedy, gdy jest to konieczne, prowadząc do znaczącej poprawy wydajności. Wyobraź sobie narzędzie do zarządzania projektami na dużą skalę, gdzie listy zadań są stale aktualizowane, usuwane i zmieniane kolejność. Bez tych optymalizacji, każda drobna zmiana w liście zadań wywoływałaby kaskadę ponownych renderowań, czyniąc aplikację powolną i nieresponsywną. Strategicznie używając useMemo, useCallback i React.memo, aplikacja może pozostać wydajna nawet przy złożonych danych i częstych aktualizacjach.

    Dodatkowe Techniki Optymalizacji

    Chociaż useMemo, useCallback i React.memo są potężnymi narzędziami, nie są jedynymi opcjami optymalizacji wydajności React. Oto kilka dodatkowych technik do rozważenia:

    Globalne Rozważania Dotyczące Optymalizacji

    Podczas optymalizacji aplikacji React dla globalnej publiczności ważne jest, aby wziąć pod uwagę takie czynniki, jak opóźnienia sieciowe, możliwości urządzeń i lokalizacja. Oto kilka wskazówek:

    Wniosek

    Optymalizacja wydajności aplikacji React jest kluczowa dla dostarczenia płynnego i responsywnego doświadczenia użytkownika. Opanowując techniki takie jak useMemo, useCallback i React.memo, a także rozważając globalne strategie optymalizacji, możesz budować wydajne aplikacje React, które skalują się, aby sprostać potrzebom zróżnicowanej bazy użytkowników. Pamiętaj, aby profilować swoją aplikację, aby identyfikować wąskie gardła wydajności i strategicznie stosować te techniki optymalizacji. Nie optymalizuj przedwcześnie – skup się na obszarach, w których możesz osiągnąć największy wpływ.

    Ten przewodnik stanowi solidną podstawę do zrozumienia i wdrożenia optymalizacji wydajności React. W miarę dalszego rozwijania aplikacji React, pamiętaj o priorytetowaniu wydajności i ciągłym poszukiwaniu nowych sposobów na poprawę doświadczenia użytkownika.