diff --git a/daweb/react/entry.yml b/daweb/react/entry.yml index 8fa11649..7c44b08e 100644 --- a/daweb/react/entry.yml +++ b/daweb/react/entry.yml @@ -4,7 +4,7 @@ lessons: - uvod-do-reactu - formulare-efekty - komunikace-dite-rodic - - komunikace-sourozenci + - pokrocila-komunikace - react-router - leviexpress-1 - leviexpress-2 diff --git a/daweb/react/komunikace-dite-rodic/shrnuti.md b/daweb/react/komunikace-dite-rodic/shrnuti.md index 3e1b4563..79807e55 100644 --- a/daweb/react/komunikace-dite-rodic/shrnuti.md +++ b/daweb/react/komunikace-dite-rodic/shrnuti.md @@ -4,4 +4,6 @@ Po této lekci byste měli vědět a znát - základní povědomí, jak probíhá komunikace mezi komponentami, - jak komponenty komunikují pomocí _props_, tedy ve směru od rodiče k dítěti, -- jak komponenty komunikují pomocí callbacků, tedy ve směru od dítěte k rodiči. +- jak komponenty komunikují pomocí callbacků, tedy ve směru od dítěte k rodiči, +- hlavní poučku pro jednoduchou komunikaci od dítěte k rodiči: + > Dítě může rodiči poslat informaci tak, že nastaví jeho stav. Rodič tak musí dítěti předat funkci, která mu umožní stav měnit. diff --git a/daweb/react/komunikace-sourozenci/entry.yml b/daweb/react/komunikace-sourozenci/entry.yml deleted file mode 100644 index 39a1df20..00000000 --- a/daweb/react/komunikace-sourozenci/entry.yml +++ /dev/null @@ -1,6 +0,0 @@ -title: Komunikace mezi sourozenci -lead: 'Nejnáročnejší typ komunikace mezi komponentami je předávání informací mezi sourozenci.' -access: 'claim' -sections: - - sourozenci - - cv-sourozenci diff --git a/daweb/react/komunikace-sourozenci/excs/produkty.md b/daweb/react/komunikace-sourozenci/excs/produkty.md deleted file mode 100644 index 213bc79a..00000000 --- a/daweb/react/komunikace-sourozenci/excs/produkty.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -title: Produkty -demand: 1 ---- - -Vytvořte si JavaScriptový program a vložte do něj následující objekt. - -```js -const product = { - name: 'Toaster', - brand: 'Tefal', - inStock: 34, - price: '$25', - colors: ['black', 'red', 'silver', 'blue', 'silver'], -}; -``` - -1. Pomocí destrukturování získejte z objektu `product` jeho název a značku. Vypište je do konzole. -1. Pomocí destrukturování získejte z objektu `product` pole barev. Uložte si jej do proměnné `productColors`. -1. Z pole `productColors` si pomocí destrukturování vytáhněte první prvek do proměnné `firstColor`. -1. Z pole `productColors` si pomocí destrukturování vytáhněte do nějakých proměnných druhý a čtvrtý prvek. -1. Zkuste pomocí destrukturingu získat druhou a čtvrtou barvu přímo z objektu `product`. diff --git a/daweb/react/komunikace-sourozenci/sourozenci.md b/daweb/react/komunikace-sourozenci/sourozenci.md deleted file mode 100644 index 29e839bd..00000000 --- a/daweb/react/komunikace-sourozenci/sourozenci.md +++ /dev/null @@ -1,57 +0,0 @@ -## Komunikace mezi sourozenci - -Komunikaci mezi sourozenci si opět ilustrujeme na našem příkladu s volbou nového prezidenta. V minulé lekci jsme skončili v situaci, kdy komponenta `Candidate` dokáže svému rodiči `App` poslat jméno kandidáta pomocí `callbacku`. Naše aplikace však byla napsaná velmi jednoduše. V praxi bychom nejspíše narazili na složitější situaci. Podívejme se na začátek komponenty `App`. - -```js -return ( -
-
-
-
-

Nový prezident

-

- { - president === null ? 'Vyberte svého kandidáta' : president - } -

-
-
-``` - -Tento úsek představující náš hrad by si jistě zasloužil samostatnou komponentu. Pojmenujme ji `Castle` a vytvoříme pro ni separátní složku i styly. Kód komponenty pak bude vypadat takto. - -```js -import React from 'react'; -import './style.css'; - -const Castle = ({ president }) => { - return ( -
-
-
-

Nový prezident

-

- {president === null ? 'Vyberte svého kandidáta' : president} -

-
-
- ); -}; - -export default Castle; -``` - -Naše komponenta `App` pak může komponentu `Castle` použíjt jako svoje dítě. - -```jsx -return ( -
- - -

Kandidátí

-); -``` - -Všimněte si, že komponenta `Candidate` a komponenta `Castle` jsou sourozenci. Jejich společným rodičem je komponenta `App`. Komponenta `Candidate` už neposílá jméno kandidáta svému rodiči jako dříve. Nyní jej posílá svému svému sourozenci `Castle`. Všimněte si však, že tato komunikace probíhá skrze rodiče `App`. Jakmile komponenta `Candidate` zavolá callback `handleVote`, tento uloží jméno prezidenta do stavu komponenty `App`. Tímto se vyvolá překreslení komponenty `App`, čimž se hodnota stavu `president` předá do props komponenty `Castle`. - -Tento princip možná na první pohled vypadá složitě. Výhodou však je, že zůstává vždy stejný. Vždy, když chceme předávat informace mezi sourozenci, předáváme je skrze stav rodiče. diff --git a/daweb/react/komunikace-sourozenci/cv-sourozenci.md b/daweb/react/pokrocila-komunikace/cv-sourozenci.md similarity index 100% rename from daweb/react/komunikace-sourozenci/cv-sourozenci.md rename to daweb/react/pokrocila-komunikace/cv-sourozenci.md diff --git a/daweb/react/komunikace-sourozenci/cvlekce/dotaznik-fajfka.md b/daweb/react/pokrocila-komunikace/cvlekce/dotaznik-fajfka.md similarity index 100% rename from daweb/react/komunikace-sourozenci/cvlekce/dotaznik-fajfka.md rename to daweb/react/pokrocila-komunikace/cvlekce/dotaznik-fajfka.md diff --git a/daweb/react/komunikace-sourozenci/cvlekce/dotaznik-odpoved.md b/daweb/react/pokrocila-komunikace/cvlekce/dotaznik-odpoved.md similarity index 100% rename from daweb/react/komunikace-sourozenci/cvlekce/dotaznik-odpoved.md rename to daweb/react/pokrocila-komunikace/cvlekce/dotaznik-odpoved.md diff --git a/daweb/react/komunikace-sourozenci/cvlekce/dotaznik.md b/daweb/react/pokrocila-komunikace/cvlekce/dotaznik.md similarity index 100% rename from daweb/react/komunikace-sourozenci/cvlekce/dotaznik.md rename to daweb/react/pokrocila-komunikace/cvlekce/dotaznik.md diff --git a/daweb/react/pokrocila-komunikace/dite-rodic.md b/daweb/react/pokrocila-komunikace/dite-rodic.md new file mode 100644 index 00000000..69b49af7 --- /dev/null +++ b/daweb/react/pokrocila-komunikace/dite-rodic.md @@ -0,0 +1,70 @@ +## Pokročilejší komunikace od dítěte k rodiči + +V předchozí lekci jsme se naučili jednoduchou komunikaci od dítěte k rodiči, která by se dala shrnout takto: + +> Dítě může rodiči poslat informaci tak, že nastaví jeho stav. Rodič tak musí dítěti předat funkci, která mu umožní stav měnit. + +My jsme proto dítěti vždycky posílali přímo funkci `setState`, tedy například `setPresident` v naší ukázce s volbami. Snadno ovšem narazíme na situace, kdy si s tímto postupem nevystačíme. Většinou to je ve chvíli, kdy chceme rodiči od dítěte předat nějakou informaci a rodič se má sám rozhodnout, jak s touto informací naloží. Zda například změní stav, jakým zůsobem jej změní nebo třeba udělá něco úplně jiného, například odešle data na server, zavolá nějaký API endpoint apod. + +Pro názornou ukázku s vraťme k našemu příkladu s volbami. V minulé lekci jsme si ukázali, jak může komponenta `Candidate` poslat informaci o tom, kdo byl zvolen, svému rodiči `HomePage`. Tato komunikace proběha srkze funkci předanou skrze prop `onVote`. + +```jsx +export const Candidate = ({ name, avatar, onVote }) => { + const handleClick = () => { + onVote(name); + }; + + return ( +
+

{name}

+ + +
+ ); +}; +``` + +Této komponentě pak její rodič `HomePage` předával rovnou funkci `setPresident`, která nastaví stav `president` na jméno kandidáta. + +```jsx +
+ {candidates.map((c) => ( + + ))} +
+``` + +Co kdybychom však chtěli, aby se po kliknutí na kandidáta zobrazilo nejdříve nějaké upozornění a až po jeho potvrzení se změnil stav `president`? Nebo bychom zároveň se změnou stavu chtěli odeslat na server informaci o tom, kdo byl zvolen? + +V takovém případě musíme udělat krok navíc a v komponentě `HomePage` vytvořit novou funkci `handleVote`, která bude obsahovat veškerou logiku, která se má provést po kliknutí na kandidáta. Tato funkce pak bude předána komponentě `Candidate` skrze prop `onVote`. + +```jsx +const handleVote = (name) => { + if (window.confirm(`Opravdu chcete zvolit kandidáta ${name}?`)) { + setPresident(name); + // zde bychom mohli odeslat data na server + } +}; +``` + +```jsx +
+ {candidates.map((c) => ( + + ))} +
+``` + +Komponenta `Candidate` se tedy chová stejně, jako prve, ale v `HomePage` máme o krok navíc. diff --git a/daweb/react/pokrocila-komunikace/entry.yml b/daweb/react/pokrocila-komunikace/entry.yml new file mode 100644 index 00000000..71c6e803 --- /dev/null +++ b/daweb/react/pokrocila-komunikace/entry.yml @@ -0,0 +1,9 @@ +title: Pokročilá komunikace +lead: Náročnejší typy komunikace mezi komponentami a jak se s nimi vypořádat +access: 'claim' +sections: + - dite-rodic + - sourozenci + - potomci + - shrnuti +# - cv-sourozenci diff --git a/daweb/react/pokrocila-komunikace/potomci.md b/daweb/react/pokrocila-komunikace/potomci.md new file mode 100644 index 00000000..1bc36775 --- /dev/null +++ b/daweb/react/pokrocila-komunikace/potomci.md @@ -0,0 +1,61 @@ +## Komunikace mezi potomky + +Náš příklad s volbami by ještě pořád mohl být o kus složitější. V reálných aplikacích se totiž setkáme s tím, že komponenty jsou do sebe zanořeny o několik úrovní hlouběji. V takovém případě se může stát, že komponenta, která potřebuje nějaká data, je od komponenty, která tato data má, vzdálena o několik svých předků. Pokud takovéto komponenty spolu potřebují komunikovat, mluvíme o komunikaici mezi potomky. + +V takové situaci másíme data předávat přes několik komponent, které tato data nepotřebují, pouze je předávají dále. Tento postup se běžně nazývá _prop drilling_, česky bychom mohli říct _vrtání_. + +Pro názorný příklad si představme, že bychom v naší aplikaci s volbami měli ještě další komponentu `CandidateList`, která by zobrazovala seznam všech kandidátů. To znamená, že komponenta `Candidate` je zanořena o jednu úrovně hlouběji a musíme k ní funkci `handleVote` provrtat přes komponentu `CandidateList`. + +```jsx +const CandidateList = ({ candidates, onVote }) => { + return ( +
+ {candidates.map((c) => ( + + ))} +
+ ); +}; +``` + +JSX v komponentě `HomePage` pak vypadá takto: + +```jsx +return ( +
+ +

Kandidátí

+ +
+); +``` + +Kdybychom si chtěli život ještě o kousek ztížit, mohli bychom si představit, že tlačítko pro volbu kandidáta je také nějaká složitější komponenta, například tlačítko s ikonou. V takovém případě bychom museli funkci `handleVote` provrtat ještě o jednu úroveň hlouběji. + +```jsx +const Candidate = ({ name, avatar, onVote }) => { + return ( +
+

{name}

+ + +
+ ); +}; +``` + +## Prop drilling v praxi + +Prop driling nám slouží k tomu, aby spolu mohly komunikovat komponenty, které jsou od sebe vzdáleny o několik úrovní hlouběji. Tato technika má však také své nevýhody. Tak hluboké vrtání, jako jsme vidělí výše, je ještě v praxi únosné, ale hlubší prop driling začiná mít zásadní nevýhody: + +1. **Horší přehlednost** – čtenář kódu musí složitě navigovat kódem a držet v hlavě, kudy všude proudí data. +1. **Nepohodlnost** – psát kód s hlubokým vrtáním je pro programátory otravné a zdlouhavé. +1. **Průchozí komponenty** – máme v kódu spoustu komponent, která data ve skutečnosti nepotřebují, jen je předávají dále, čímž se komplikuje jejich kód. +1. **Horší udržitelnost** – pokud se rozhodneme změnit strukturu komponent, musíme přepisovat i průchozí komponenty, která data vlastně nepotřebují. + +V reálnách aplikacích se proto příliš agresivnímu prop drilingu snažíme vyhnout. Pokud to z hlediska struktury aplikace dává smysl, snažíme se předávání dat mezi komponentami řešit jinými způsoby, například pomocí _contextu_ nebo pomocí _state managementu_. To jsou však pro tento kurz příliš pokročilá témata. V následujících lekcích se proto omezíme na vrtání maximálně přes jednu komponentu, nebo se mu budeme vyhýbat úplně. diff --git a/daweb/react/pokrocila-komunikace/shrnuti.md b/daweb/react/pokrocila-komunikace/shrnuti.md new file mode 100644 index 00000000..7afad180 --- /dev/null +++ b/daweb/react/pokrocila-komunikace/shrnuti.md @@ -0,0 +1,8 @@ +## Shrnutí + +Po této lekci byste měli vědět a znát + +- jak zařídit pokročilejší komunikaci od dítěte k rodiči, +- jak funguje komunikace mezi sourozenci, +- k čemá slouží prop drillling a jak jej použít pro komunikaci mezi potomky, +- jaké jsou nevýhody a úskalí hlubokého prop drillingu a proč se mu snažíme vyhnout. diff --git a/daweb/react/pokrocila-komunikace/sourozenci.md b/daweb/react/pokrocila-komunikace/sourozenci.md new file mode 100644 index 00000000..d5521b73 --- /dev/null +++ b/daweb/react/pokrocila-komunikace/sourozenci.md @@ -0,0 +1,59 @@ +## Komunikace mezi sourozenci + +Komunikaci mezi sourozenci je potřeba ve chvíli, kdy máme si potřebují nějaká data vyměnit komponenty, které mají společného rodiče. + +Tuto situaci si opět ilustrujeme na našem příkladu s volbou nového prezidenta. V minulé lekci jsme skončili v situaci, kdy komponenta `Candidate` dokáže svému rodiči `HomePage` poslat jméno kandidáta pomocí callbacku `onVote`. Naše aplikace však byla napsaná stále dosti jednoduše. V realitě bychom nejspíše narazili na složitější situaci. Podívejme se na začátek komponenty `HomePage`. + +```js +return ( +
+
+
+
+

Nový prezident

+

+ { + president === null ? 'Vyberte svého kandidáta' : president + } +

+
+
+``` + +Tento úsek představující náš hrad by si jistě zasloužil samostatnou komponentu. Pojmenujme ji `Castle` a vytvoříme pro ni separátní složku i styly. Kód komponenty pak bude vypadat takto. + +```js +import React from 'react'; +import './style.css'; + +export const Castle = ({ president }) => { + return ( +
+
+
+

Nový prezident

+

+ {president === null ? 'Vyberte svého kandidáta' : president} +

+
+
+ ); +}; +``` + +Naše komponenta `HomePage` pak může komponentu `Castle` použíjt jako svoje dítě. + +```jsx +return ( +
+ + +

Kandidátí

+); +``` + +Všimněte si, že komponenta `Candidate` a komponenta `Castle` jsou sourozenci. Jejich společným rodičem je komponenta `HomePage`. Komponenta `Candidate` už neposílá jméno kandidáta svému rodiči jako dříve. Nyní jej posílá svému sourozenci `Castle`. Všimněte si však, že tato komunikace probíhá skrze rodiče `HomePage`. Jakmile komponenta `Candidate` zavolá callback `handleVote`, tento uloží jméno prezidenta do stavu komponenty `App`. Tímto se vyvolá překreslení komponenty `Home`, čimž se hodnota stavu `president` předá do props komponenty `Castle`. + +Z této ukázky plyne pravidlo pro komunikaci mezi sourozenci: + +> Komponenta může poslat informaci svému sourozenci tak, že změní stav svého rodiče. Tento stav pak bude předán jako props jinému dítěti.