-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #667 from Czechitas-podklady-WEB/666-react-4-aktua…
…lizace-textu-lekce React 4: Aktualizace textu lekce
- Loading branch information
Showing
14 changed files
with
211 additions
and
87 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 ( | ||
<div className="candidate"> | ||
<h3 className="candidate__name">{name}</h3> | ||
<img className="candidate__avatar" src={avatar} /> | ||
<button onClick={handleClick} className="btn-vote"> | ||
Vybrat | ||
</button> | ||
</div> | ||
); | ||
}; | ||
``` | ||
|
||
Této komponentě pak její rodič `HomePage` předával rovnou funkci `setPresident`, která nastaví stav `president` na jméno kandidáta. | ||
|
||
```jsx | ||
<div className="candidate-list"> | ||
{candidates.map((c) => ( | ||
<Candidate | ||
key={c.name} | ||
name={c.name} | ||
avatar={c.avatar} | ||
onVote={setPresident} | ||
/> | ||
))} | ||
</div> | ||
``` | ||
|
||
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 | ||
<div className="candidate-list"> | ||
{candidates.map((c) => ( | ||
<Candidate | ||
key={c.name} | ||
name={c.name} | ||
avatar={c.avatar} | ||
onVote={handleVote} | ||
/> | ||
))} | ||
</div> | ||
``` | ||
|
||
Komponenta `Candidate` se tedy chová stejně, jako prve, ale v `HomePage` máme o krok navíc. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 ( | ||
<div className="candidate-list"> | ||
{candidates.map((c) => ( | ||
<Candidate | ||
key={c.name} | ||
name={c.name} | ||
avatar={c.avatar} | ||
onVote={onVote} | ||
/> | ||
))} | ||
</div> | ||
); | ||
}; | ||
``` | ||
|
||
JSX v komponentě `HomePage` pak vypadá takto: | ||
|
||
```jsx | ||
return ( | ||
<div className="container"> | ||
<Castle president={president} /> | ||
<h2>Kandidátí</h2> | ||
<CandidateList candidates={candidates} onVote={handleVote} /> | ||
</div> | ||
); | ||
``` | ||
|
||
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 ( | ||
<div className="candidate"> | ||
<h3 className="candidate__name">{name}</h3> | ||
<img className="candidate__avatar" src={avatar} /> | ||
<VoteButton onVote={onVote} /> | ||
</div> | ||
); | ||
}; | ||
``` | ||
|
||
## 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ě. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 ( | ||
<div className="container"> | ||
<div className="castle"> | ||
<div className="castle__image"></div> | ||
<div className="castle__body"> | ||
<h1>Nový prezident</h1> | ||
<p className="castle__president"> | ||
{ | ||
president === null ? 'Vyberte svého kandidáta' : president | ||
} | ||
</p> | ||
</div> | ||
</div> | ||
``` | ||
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 ( | ||
<div className="castle"> | ||
<div className="castle__image"></div> | ||
<div className="castle__body"> | ||
<h1>Nový prezident</h1> | ||
<p className="castle__president"> | ||
{president === null ? 'Vyberte svého kandidáta' : president} | ||
</p> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
``` | ||
Naše komponenta `HomePage` pak může komponentu `Castle` použíjt jako svoje dítě. | ||
```jsx | ||
return ( | ||
<div className="container"> | ||
<Castle president={president} /> | ||
|
||
<h2>Kandidátí</h2> | ||
); | ||
``` | ||
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. |