Hook pro optimalizaci výkonu useCallback v Reactu
V této lekci se podíváme na následující
hook pro optimalizaci výkonu
useCallback.
Hook useCallback je podobný API useMemo,
rozdíl spočívá v tom, že první
ukládá do mezipaměti hodnotu mezi okamžiky překreslování
obrazovky, zatímco druhý - callback.
To nám umožňuje nespouštět náročné
funkce, když to není potřeba a může
být použito při
předávání funkce
do podřízených komponent.
Pojďme se na to podívat podrobněji na příkladu.
Nejprve vytvoříme komponentu App
a v ní vytvoříme stav num:
const [num, setNum] = useState(0);
Nechť máme tlačítko, po kliknutí
na které se num zvýší
o 1, a odstavec, ve kterém
budeme vypisovat hodnotu num:
return (
<div>
<button onClick={() => setNum(num + 1)}>click</button>
<p>clicks: {num}</p>
</div>
);
A teď předpokládejme, že v
App se vypisuje ještě nějaký seznam
s prvky, který budeme doplňovat
stisknutím jiného tlačítka. Pro uchování
prvků tohoto seznamu vytvoříme
stav items:
const [items, setItems] = useState([]);
A poté napíšeme funkci addItem
pro jejich přidání:
function addItem() {
setItems([...items, 'new item']);
}
Nyní napišme kód pro zobrazení
prvků seznamu a vyčleňme jej do podřízené
komponenty Items, která ve formě
props obdrží pole prvků
a funkci pro jejich přidání. Nezapomeňme
přidat výpis do konzole, abychom viděli,
kdy se naše Items bude
překreslovat:
function Items({ items, addItem }) {
const result = items.map((item, index) => {
return <p key={index}>{item}</p>;
});
console.log('Items render');
return (
<div>
<h3>Our items</h3>
{result}
<button onClick={addItem}>add item</button>
</div>
);
}
export default Items;
Umístíme Items na konec komponenty
App a budeme jí předávat pole
items a funkci pro přidání
prvků addItem:
return (
<>
<div>
<button onClick={() => setNum(num + 1)}>click</button>
<p>clicks: {num}</p>
<br />
</div>
<Items items={items} addItem={addItem} />
</>
);
A teď klikněme na tlačítka
a přesvědčme se, že num roste a
nové prvky se přidávají do seznamu.
A otevřením konzole uvidíme, že
náš seznam se překresluje pokaždé,
i když klikáme na tlačítko,
které zvyšuje num.
Pokud máme malý seznam, pak je vše
v pořádku, ale co když se předpokládá, že
bude objemný a bude tam ještě spousta věcí?
Žádný problém - řeknete si, vždyť v předchozí
lekci jsme probrali API memo,
abychom se právě vyhnuli zbytečným překreslením
komponenty.
Takže pojďme obalit naši komponentu
Items do memo a hotovo.
Mimochodem, to lze provést přímo
při exportu Items:
export default memo(Items);
Nezapomeňme importovat memo:
import { memo } from 'react';
A teď otevřeme konzoli a klikněme
na tlačítka. Všechny snahy byly marné! My
jsme komponentu memoizovali, ale při stisknutí
tlačítka 'click' se komponenta
Items stále
překresluje pokaždé.
Věc se má tak, že když se nadřazená
komponenta překresluje, její funkce
se znovu vytvářejí - to se týká i naší
funkce addItem, kterou předáváme do
Items.
Právě v tomto okamžiku nám pomůže hook
useCallback. Pojďme jej použít.
Nejprve jej importujme do
App:
import { useCallback } from 'react';
Poté přepišme prosté deklarování funkce
addItem na
Function Expression, uvedeme jako
první parametr pro useCallback
naši funkci ve formě callbacku. Jako druhý
parametr v hranatých závorkách uvedeme
závislosti - všechny reaktivní proměnné,
zúčastněné ve funkci, v našem případě
je to pole items:
const addItem = useCallback(() => {
setItems(() => [...items, 'New item']);
}, [items]);
Hotovo! Tímto způsobem jsme funkci
zakonzervovali. Klikněme znovu na tlačítka a
uvidíme, že nyní při stisknutí tlačítka
'click' se naše podřízená komponenta
nepřekresluje.
Vytvořte komponentu App, umístěte
do ní odstavec s textem. Vytvořte
stav s počáteční hodnotou 'text'
a vypište jej v odstavci. Nechť po kliknutí
na odstavec se na konec textu
přidá vykřičník.
Vytvořte podřízenou komponentu Products,
ve které budete mít tlačítko pro přidání
nového produktu. Umístěte ji v App.
V nadřazené komponentě vytvořte stav
s polem produktů a funkci přidání
nového produktu. Předajte je do
podřízené komponenty, vypište v ní
předané pole ve formě seznamu ul.
V Products vypište do konzole text
'products render'.
Obalujte Products do memo.
Klikejte na odstavec a tlačítko. Přesvědčte se,
že při kliknutí na odstavec se podřízená komponenta
stále překresluje.
Zakonzervujte funkci pro přidání
produktů, obalte ji do hooku useCallback.
Klikejte na odstavec a tlačítko. Přesvědčte se,
že při kliknutí na odstavec se podřízená komponenta
již nepřekresluje.