• Home
  • ReactJs
  • Hooki React – useCallback tutorial i komponent wyższego rzędu React.memo

Hooki React – useCallback tutorial i komponent wyższego rzędu React.memo



UseCallback, podobnie jak hook useMemo, jest przydatny w sytuacji, gdy chcesz poprawić wydajność swojej aplikacji. Dzięki temu można uniknąć niepotrzebnych renderowań, dzięki czemu aplikacja może działać szybciej.

UseCallback zwraca zapamiętaną wersję funkcji, która zmienia się tylko wtedy, gdy zmienia się jedna z zależności. Oznacza to, że jeśli masz element rodzica z elementami dziećmi, to dzieci renderowane są za każdym razem, gdy rodzic jest renderowany, nawet, jeśli ich zawartość się nie zmieniła. Można jednak uniknąć renderowania dzieci, jeśli zamiast zwykłej funkcji przejdziesz do nich funkcję owiniętą w hook useCallback, i jednocześnie owiniesz komponent dziecko w komponent wyższego rzędu React.memo. Brzmi strasznie? Zobaczmy to na przykładzie:

Komponent App.js zawiera nasz komponent nadrzędny o nazwie HookExample:

import React from 'react';
import HookExample from './components/hookExample.js';

function App() {
    return (
        <HookExample />
    );
}

export default App;

Jak dotąd jest łatwo. Teraz zobaczmy, co zawiera komponent nadrzędny:

const HookExample = () => {    
    const [counter, setCounter] = useState(0);

    const changeCounter = (sign) => {
        if (sign === "+") {
            setCounter(c => c + 1);
        }
        else {
            setCounter(c => c - 1);
        }
    }

    console.log("Parent",);
    return (
        <div className="App">
            <div>
                <p>Counter: {counter} </p>
                <Child2 changeCounter={changeCounter}/>
            </div>
        </div>
    );
}

export default HookExample;

Komponent rodzic zawiera stan licznika i funkcję changeCounter, która zmienia wartość licznika. Zwraca zaś wartość licznika i komponent dziecko, do którego przekazuje funkcję changeCounter.



Komponent dziecko wygląda tak:

import React from 'react';

const Child = ({changeCounter}) => {

    console.log("Child");
    return (
        <div style={{backgroundColor: "blue", color: "white"}}>
            <p>Child:</p>
            <div>
                <button onClick={() => changeCounter("-") }>-1</button>
                <button onClick={() => changeCounter("+") }>+1</button>
            </div>
        </div>
    )
};

export default Child;

Teraz za każdym razem, gdy klikniesz przycisk +1 lub -1, zobaczysz, że w konsoli są rejestrowane dwie linie kodu: jedna z komponentu rodzica i jedna z komponentu dziecka. Wyobraź sobie teraz, że masz 100 komponentów dzieci w komponencie rodzicu. Każdy z nich jest renderowany, więc każdy na nich wyświetli jedną linię kodu, albo wykona inne obliczenia, które w nim umieścisz. Zajmuje to trochę czasu i zasobów i jest niepotrzebne, jeśli jakiekolwiek dane przekazywane dzieciom nie ulegają zmianie. Tak jak wspomniałam wcześniej, można uniknąć renderowania dzieci i oszczędzić czas i zasoby, przekazując im funkcję opakowaną w useCallback:

const changeCounter = useCallback(
        (sign) => {
            if (sign === "+") {
                setCounter(c => c + 1);
            }
            else {
                setCounter(c => c - 1);
            }
        }, [setCounter]
) 


Pamiętaj również o owinięciu komponentu dziecka w komponent wyższego rzędu React.memo:

const Child = React.memo(({changeCounter}) => {

    ...
});

Teraz, jeśli klikniesz przycisk +1 lub -1, zobaczysz, że tylko rodzic wyświetlił kod w konsoli, a komponent dziecko nie. UseCallback przekazał zapamiętaną wersję funkcji do komponentu dziecka, a jeśli jej zależności (w tym przypadku funkcja setCounter) nie ulegną zmianie, komponent dziecko zawsze otrzyma te same właściwości. Ponieważ owinąłeś komponent dziecko w komponent wyższego rzędu React.memo, który działa podobnie do React.PureComponent, ale jest używany tylko w komponentach funkcyjnych, gdy komponent dziecko otrzyma te same właściwości co poprzednio, React pominie renderowanie komponentu i ponownie użyje ostatniego wyrenderowanego wyniku.

Według dokumentacji „Ta metoda istnieje tylko jako optymalizacja wydajności. Nie polegaj na niej, aby „zapobiegać” renderowaniu, ponieważ może to prowadzić do błędów ”.



Zobacz DEMO  i sprawdź, jak działa hook useCallback

Kod do tego postu możesz naleźć tu: https://github.com/love-coding-pl/React-Hooks-Examples/tree/Hook-7-useCallback

Joanna

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *