Lekce 2 - Vykreslování v Reactu a jeho optimalizace
V předchozí lekci, Úvod do ekosystému Reactu, jsme si řekli něco o základech Reactu a představili jsme si jeho vybrané knihovny. Ukázali jsme si také, kde hledat informace o dostupných rozšířeních a podle čeho je vybírat.
V následujícím tutoriálu pokročilého Reactu se podíváme pod pokličku Reactu, abychom porozuměli, jak probíhá vykreslování. Napíšeme si k tomu krátkou aplikaci, na níž si proces vykreslování vysvětlíme. I když React je sám o sobě optimalizovaný pro rychlé vykreslování, existují techniky, které nám umožní ještě více zvýšit výkon našich aplikací. V druhé části tutoriálu se proto zaměříme na tři klíčové optimalizační techniky, konkrétně na memoizaci, lazy loading a virtualizaci.
Jak funguje vykreslování v Reactu
Vykreslování v Reactu je založeno na konceptu virtuálního DOM (Document Object Model). Na rozdíl od skutečného DOM, který představuje strukturu webové stránky v prohlížeči, je virtuální DOM lehkou, in-memory reprezentací skutečného DOM. React udržuje tuto virtuální reprezentaci a porovnává ji s aktuálním stavem DOM. Kdykoli dojde k změně v komponentě, React tuto změnu nejprve aplikuje na virtuální DOM, porovná starý a nový virtuální DOM, a pak efektivně aktualizuje skutečný DOM tím, že upraví jen ty části, které se skutečně změnily. Tento přístup pomáhá minimalizovat nákladné operace s DOMem a zvyšuje výkon aplikace.
Podívejme se na celý proces blíže:
- Inicializace React aplikace - jakmile se aplikace poprvé načte, React vytvoří virtuální DOM podle její komponentové hierarchie.
- Renderování - v momentu, kdy se změní stav nebo vstupní data aplikace, React vyvolá proces renderování. Každá komponenta ve stromě se renderuje do virtuálního DOM.
- Porovnání s předchozím stavem - React porovná nový
virtuální DOM s předchozím stavem virtuálního DOM. Tento krok se nazývá
reconciliation
(srovnání). - Vytvoření rozdílů (
diffing
) - React určí rozdíly mezi novým a starým virtuálním DOM. To jsou změny, které je třeba provést na skutečném DOM. - Aktualizace skutečného DOM - na základě rozdílů určených v předchozím kroku provede React aktualizaci na skutečném DOM.
Tento proces, jak jsme si už řekli, umožňuje Reactu rychle reagovat na změny a minimalizovat zbytečné aktualizace DOM, což vede k lepšímu výkonu.
Příklad vykreslování aplikace
Představme si nyní proces vykreslování na reálné aplikaci s následující komponentovou hierarchií:
- Jakmile se načte React aplikace, začne se vykreslovat kořenová
komponenta
App
. - Komponenta
App
vykreslí své dětské komponenty:Header
,MainComponent
aFooter
. - Komponenta
MainComponent
vykreslí i své dítěMainCompChild
. - Pokud dojde ke změně stavu v komponentě
MainComponent
, React v ní provede aktualizaci stavu. - React porovná nový virtuální DOM (po aktualizaci) s předchozím virtuálním DOM (po vykreslení).
- React identifikuje rozdíly mezi novým a starým virtuálním DOM a určí, které části stránky byly změněny.
- Nakonec React aktualizuje skutečný DOM pouze pro komponentu
MainComponent
a pro její dítě,MainCompChild
.
Výsledek potom vypadá takto:
Aplikace ukazující vykreslování v praxi
Teorii už tedy známe a je na čase vyzkoušet si znalosti v praxi. Společně si tedy vytvoříme jednoduchou aplikaci, kde názorně uvidíme, jak vykreslování v Reactu funguje:
Založení projektu
V počítači si vytvoříme složku pro projekt a otevřeme si ji ve
vybraném editoru kódu. Otevřeme si terminál a vytvoříme novou React
aplikaci s názvem vykreslovani
:
Založení projektu:
npx create-react-app vykreslovani
Pak změníme adresář na ten s novou aplikací (vykreslovani/
)
a spustíme lokální server na http://localhost:3000/
:
Spuštění serveru: cd vykreslovani npm start
Příprava komponent
Naše kořenová komponenta je App.js
. Kód, který bude
obsahovat funkci App()
v souboru App.js
, vypadá
takto:
function App() { console.log("aplikace") return ( <div className="App"> <h1>Aplikace</h1> </div> ); } export default App;
V podobném duchu teď vytvoříme další komponenty ze stromu komponent.
Každá komponenta obsahuje nadpis se svým názvem a také
console.log
s jasným identifikátorem, abychom pak v konzoli mohli
sledovat vykreslování.
Záhlaví
Vytvoříme soubor Header.js
s kódem:
function Header() { console.log("hlavicka") return ( <div> <h2>Záhlaví</h2> </div> ) } export default Header;
Hlavní komponenta
Vytvoříme soubor MainComponent.js
s kódem:
import {useState} from 'react'; import MainCompChild from './MainCompChild'; function MainComponent() { console.log("hlavni komponenta"); const [count, setCount] = useState(0); const incrementCount = () => { setCount((prevCount) => prevCount + 1); // Zvýší stav o 1 vzhledem k předchozímu stavu }; return ( <div style={{border: "2px solid"}}> <h2>Hlavní komponenta</h2> <p>Počet: {count}</p> <button onClick={incrementCount}>+</button> <MainCompChild /> </div> ) } export default MainComponent
Hlavní komponenta obsahuje jednoduché počítadlo, které po klikání na
tlačítko se symbolem plus (+
) připočítává k číslu
jedničku. Dosahujeme toho pomocí změny stavu. Komponentě definujeme také
border
, ať vizuálně vidíme, že obsahuje také počítadlo a
své dítě.
Do hlavní komponenty jsme si již importovali její dítě a také jej v ní vykreslujeme. Teď je čas dítě vytvořit v projektu.
Dítě hlavní komponenty
Vytvoříme si soubor MainCompChild.js
s kódem:
function MainCompChild() { console.log("dite hlavni komponenty") return ( <div> <h3>Dítě hlavní komponenty</h3> </div> ); } export default MainCompChild;
Patička
No a na závěr si vytvoříme v projektu soubor Footer.js
s
kódem:
function Footer() { console.log("paticka") return ( <div> <h2>Patička</h2> </div> ) } export default Footer;
Tím máme všechny potřebné komponenty hotové.
Import do App.js
a vykreslení komponent
Je tedy čas importovat všechny vytvořené komponenty do souboru
App.js
:
import Header from './Header'; import MainComponent from './MainComponent'; import Footer from './Footer';
Pod tag <h1>
s nadpisem Aplikace
pak
vykreslíme importované komponenty:
<Header />
<MainComponent />
<Footer />
Sledování vykreslování v konzoli
Otevřeme si naši aplikaci v prohlížeči, klikneme pravým tlačítkem myši a otevřeme vývojářské nástroje. V nich přejdeme do konzole. Pokud je v konzoli již něco vypsané, smažeme ji. Následně obnovíme naši stránku. V konzoli se vypíši názvy všech našich komponent, protože se právě všechny iniciálně vykreslily:
Po kliknutí na tlačítko Plus se změní stav v hlavní komponentě. V konzoli hned vidíme, jak se opět vykreslí pouze tato hlavní komponenta a její dítě. To se opakuje po každém kliknutí na tlačítko:
Praktickou ukázku tedy máme za sebou a můžeme se pustit do slíbených optimalizačních technik.
Techniky optimalizace vykreslování
I když React vykonává vykreslování efektivně, existují situace, kdy můžeme jeho výkon ještě zlepšit.
Memoizace
Pomocí memoizace dokážeme uchovávat v paměti výsledky
dřívějších výpočtů, čímž se vyhneme opakovanému výpočtu stejných
hodnot. To je užitečné zejména v komponentách, které obsahují náročné
výpočty. Jednou z nejběžnějších technik memoizace v JavaScriptu je
použití tzv. memoizačních knihoven, jako je například memo
z
Reactu, nebo knihovna lodash.memoize
.
V Reactu lze memo
použít pomocí hooku useMemo()
.
Hook přijímá dvě hlavní věci: funkci a pole závislých hodnot. Funkce,
kterou předáme useMemo()
, pak provádí výpočet nebo operaci,
kterou chceme memoizovat. Pole závislých hodnot potom obsahuje všechny
hodnoty, které jsou relevantní pro výpočet. Pokud se některá z těchto
hodnot změní, useMemo()
znovu provede výpočet.
Hook vrací memoizovaný výsledek výpočtu. Tento výsledek se nezmění, pokud se nezmění závislé hodnoty, což umožňuje zabránit zbytečnému vykonávání výpočtů při každém renderování komponenty.
Zatímco hooky jako useMemo()
se používají ve
funkcionálních komponentách, pokud pracujeme s projektem, který má
třídní komponenty, lze pro memoizaci použít nástroje jako
shouldComponentUpdate
nebo PureComponent
.
Lazy loading
Lazy loading umožňuje načítat komponenty až tehdy, když jsou potřeba. Tím dokážeme zrychlit počáteční načítání aplikace.
Jedním z nejběžnějších případů použití lazy loading je líné
načítání obrázků. Namísto toho, aby se všechny obrázky stáhly
najednou, jsou obrázky stahovány až tehdy, když jsou viditelné na
obrazovce. Lazy loading se používá také pro code splitting
. To
znamená, že části kódu se načítají až tehdy, když jsou potřeba. Také
tímto způsobem lze zlepšit výkon aplikace, a to snížením objemu kódu,
který se musí stáhnout při prvním načtení stránky.
Virtualizace
Virtualizace umožňuje efektivně zobrazovat a spravovat velké seznamy dat na webových stránkách. Místo toho, aby byla vytvořena a vykreslena každá položka seznamu, jako je to v klasickém přístupu, virtualizace načítá a vykresluje pouze viditelné položky. To zvyšuje výkon a snižuje paměťovou zátěž. Virtualizace se obvykle využívá právě v kombinaci s lazy loadingem, kde se položky seznamu načítají až tehdy, kdy jsou potřeba (například při posunu dolů nebo nahoru).
Se všemi zmíněnými technikami se v průběhu kurzu detailně seznámíme.
V následující lekci, Serverové renderování s Next.js, se budeme zabývat frameworkem Next.js a serverovým renderováním.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 11x (320.06 kB)
Aplikace je včetně zdrojových kódů v jazyce JavaScript