Skip to content

Commit

Permalink
Merge pull request #662 from Czechitas-podklady-WEB/656-react-3-aktua…
Browse files Browse the repository at this point in the history
…lizace-lekce

React 2: Aktualizace obsahu lekce
  • Loading branch information
podlomar authored Nov 4, 2023
2 parents 033ce33 + 6976f82 commit 4cfb131
Show file tree
Hide file tree
Showing 10 changed files with 70 additions and 45 deletions.
7 changes: 5 additions & 2 deletions daweb/react/komunikace-dite-rodic/cv-komunikace.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
## Cvičení: Komunikace

::exc[cvlekce/komunikace]
::exc[cvlekce/potisk-tricek]
::exc[cvlekce/kurzovni-listek-zaklad]
::exc[cvlekce/kurzovni-listek-api]
::exc[cvlekce/hamburger-menu]
::exc[cvlekce/nazev-stranky]

<!-- ::exc[cvlekce/hamburger-menu]
::exc[cvlekce/nazev-stranky] -->
11 changes: 6 additions & 5 deletions daweb/react/komunikace-dite-rodic/cvlekce/hamburger-menu.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
---
title: Hamburger menu
lead: Vytvořte hamburger menu, které se otevírá a zavírá.
demand: 3
solutionAccess: lock
---

Nyní náš čeká složitější případ komunikace, kdy se předává informace směrem od dítěte k rodiči pomocí callbacku. Nejdříve si procvičíme callback bez parametrů.
Nyní náš čeká složitější případ komunikace, kdy se předává informace směrem od dítěte k rodiči pomocí callbacku.

1. Vytvořte si repozitář ze šablony [cviceni-hamburger](https://github.com/Czechitas-podklady-WEB/cviceni-hamburger) obsahující React stránku s jednoduchým hamburger menu. Prohlédněte si připravený kód.
1. V komponentě `App` vytvořte stav `menuOpened`, který bude obsahovat hodnotu `true` nebo `false` podle toho, zda má být menu otevřeno nebo zavřeno. Stav ovládejte kliknutím na tlačítko `.menu__btn`.
1. V komponentě `HomePage` vytvořte stav `menuOpened`, který bude obsahovat hodnotu `true` nebo `false` podle toho, zda má být menu otevřeno nebo zavřeno. Stav ovládejte kliknutím na tlačítko `.menu__btn`.
1. Dle hodnoty ve stavu `menuOpened` správně sestavte třídu pro element `.menu`. K zavření menu slouží CSS třída `menu--closed`.
1. Nyní budeme chtít zařídit, aby se hamburger menu zavřelo po kliknutí na libovolný odkaz. Uvnitř komponenty `App` tedy vytvořte callback funkci `handleSelectItem`, která změní hodnotu stavu `menuOpened` na `false`.
1. Chceme, aby komponenta `MenuItem` přijímala prop s názvem `onSelect`. Ta bude očekávat callback, který se zavolá, když uživatel vybere danou položku. Předejte tedy callback `handleSelectItem` všem komponentám `MenuItem` jako prop s názvem `onSelect`.
1. Uvnitř komponenty `MenuItem` zajistěte, aby se předaný callback zavolal při kliknutí na položku odkazu.
1. Chceme, aby komponenta `MenuItem` přijímala prop s názvem `onChangeVisible`. Ta bude očekávat callback, který se zavolá s hodnotou `false`, když uživatel vybere danou položku, aby se menu zavřelo. Přidejte tedy na prvek `<a>` posluchač události `onClick`, který zavolá předaný callback s hodnotou `false`.
1. V komponentě `HomePage` předejte všem instancím komponenty `MenuItem` skrze _prop_ `onChangeVisible` funkci měnící stav.
9 changes: 9 additions & 0 deletions daweb/react/komunikace-dite-rodic/cvlekce/komunikace.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
title: Základy komunikace
lead: Vyzkoušejte si základy komunikace mezi komponentami.
demand: 3
solutionAccess: lock
---

1. Vytvořte si repozitář ze šablony [cviceni-komunikace](https://github.com/Czechitas-podklady-WEB/cviceni-komunikace).
1. Následujte instrukce z README repozitáře.
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
---
title: Kurzovní lístek, API
lead: Získávejte kurzy měn z veřejného API.
demand: 2
solutionAccess: lock
---

Jistě cítíte, že mít kurzy měn zadrátované přímo v kódu aplikace není zrovna užitečné. V tomto cvičení získáme kurzy z veřejného API jako praví profesionálové.
Jistě cítíte, že mít kurzy měn zadrátované přímo v kódu aplikace není zrovna užitečné. V tomto cvičení získáme kurzy z veřejného API jako praví profesionálové. Opět zatím budeme používat komunikaci pouze směrem od rodiče k dítěti, tedy budeme spíše opakovat práci s _props_ a efekty.

Chceme-li získat kurz amerického dolaru, můžeme využít následující API.

Expand All @@ -12,5 +14,4 @@ https://api.frankfurter.app/latest?from=USD&to=CZK
```

1. Prohlédněte si data, která API vrací. Zkuste do URL jako parametr `from` zadat nějakou jinou měnu, například GBP nebo CHF, a podívejte se, jak se data změní.
1. Upravte komponentu `Rate` tak, aby si z API stáhla správný kurz pro měnu, kterou dostane v prop `from`.
1. Zařiďte, aby se správná data stáhla kdykoliv, když se změní hodnota uvnitř prop `from`. K tomu budete potřebovat specializovaný `useEffect`.
1. Upravte komponentu `Rate` tak, aby si z API stáhla správný kurz pro měnu, kterou dostane v prop `from`. Zařiďte, aby se správná data stáhla kdykoliv, když se změní hodnota uvnitř _prop_ `from`. K tomu budete potřebovat `useEffect` se závislostí na _prop_ `from`.
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
---
title: Kurzovní lístek, základ
lead: Vytvořte aplikaci, která zobrazuje aktuální kurzy měn.
demand: 2
solutionAccess: lock
---

Komunikaci směrem od rodiče k dítěti si procvičíme na aplikaci, která převádí různé světové měny na české koruny.
Rozhodně není od věci procvičit si také komunikaci směrem od rodiče k dítěti. To si vyzkoušíme na aplikaci, která převádí různé světové měny na české koruny. Vzhledem k tomu, že tento typ komunikace se odehrává prostě předáváním _props_, bude toto cvičení spíš opakování toho, co už znáte z minulách lekcí.

1. Vytvořte si repozitář ze šablony [cviceni-currencies](https://github.com/Czechitas-podklady-WEB/cviceni-currencies) obsahující React stránku s jednoduchým formulářem pro kurzy měn.
1. Pomocí `npm install` nainstalujte závislosti a spusťte aplikaci. Zatím nic zásadního nedělá.
1. Prohlédněte si připravený kód a strukturu projektu. Všimněte si komponmenty `Rate`, která zobrazuje kurz.
1. Do komponenty `Rate` přidejte prop `from`, která bude obsahovat kód měny, ze které chceme konvertovat na české koruny. Zařiďte, aby komponenta zobrazila kód měny, který uživatel vybere z nabídky. Toto bude komunikace od rodiče (komponenta `App`) k dítěti (komponenta `Rate`).
1. Upravate komponentu `Rate` tak, aby zobrazila správný kurz podle připravných dat v objektu `currencies`. Výslední kurz zobrazte v elementu `.rate__value`.
1. Do komponenty `Rate` přidejte prop `from`, která bude obsahovat kód měny, ze které chceme konvertovat na české koruny. Zařiďte, aby komponenta zobrazila kód měny, který uživatel vybere z nabídky. Toto bude komunikace od rodiče (komponenta `HomePage`) směrem k dítěti (komponenta `Rate`).
1. Upravate komponentu `Rate` tak, aby zobrazila správný kurz podle připravných dat v objektu `currencies`. Výsledná kurz zobrazte v elementu `.rate__value`.
4 changes: 3 additions & 1 deletion daweb/react/komunikace-dite-rodic/cvlekce/nazev-stranky.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
---
title: Název stránky
lead: Vyzkoušejte si callback s parametrem.
demand: 3
solutionAccess: lock
---

Pokračujte v předchozím příkladu. Nyní si vyzkoušíme callback s parametrem a budeme chtít, aby se při kliknutí na položku menu zobrazil správný název stránky.

1. Přidejte do komponenty `App` stav s názvem `pageTitle`, který bude představovat název aktuální stránky. Jeho výchozí hodnotu nastavte na `Domů` a použijte tento stav uvnitř elementu `h1`.
1. Přidejte do komponenty `HomaPage` stav s názvem `pageTitle`, který bude představovat název aktuální stránky. Jeho výchozí hodnotu nastavte na `Domů` a použijte tento stav uvnitř elementu `h1`.
1. Zařiďte, aby komponenta `MenuItem` při volání funkce `onSelect` zavolala tuto funkci se vstupem, který udává název stránky, který se má zobrazit. Takto předá název stránky rodičovské komponentě.
1. Do funkce `handleSelectItem` přidejte parametr `page` a nastavte stav `pageTitle` na hodnotu z tohoto parametru.
20 changes: 20 additions & 0 deletions daweb/react/komunikace-dite-rodic/cvlekce/potisk-tricek.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
title: Potisk triček
lead: Vdechněte život aplikaci na potisk triček.
demand: 3
solutionAccess: lock
---

Pomocí Reactu, stavu a komunikace mezi komponentami rozchodíme aplikaci, kde si uživatel může objednat typ trička, jeho barvu a potisk.

1. Vytvořte si repozitář ze šablony [cviceni-tricka](https://github.com/Czechitas-podklady-WEB/cviceni-tricka), repozitář si poté naklonujte a rozběhněte si základ aplikace.
1. Dobře si aplikaci prohlédněte. Vykoušejte si, jaké _props_ můžete zadat do komponenty `TShirt`, kromě barvy a textu potisku můžete také zvolit typ trička:
- `normalShortSleeve`
- `normalLongSleeve`
- `tallLongSleeve`
- `normalNoSleeve`
- `tallNoSleeve`
Zkuste si zadat různé _props_ a vyzkoušejte, co komponenta zobrazí.
1. Vaším úkolem bude zprovozni komunikaci od komponenty `TShirtSetup` ke komponentě `HomePage`, tedy komunikace od dítěte k rodiči. V `HomePage` budou potřeba tři stavy: jeden pro typ trička, jeden pro barvu a jeden pro potisk. Vytvořte tyto stavy a napojte je na komponentu `TShirt`, aby zobrazovala to, co je ve stavech.
1. V komponentě `TShirtSetup` vytvořte prop `onTypeChange`. Pomocí této funkce budeme měnit stav v rodiči. Použijte tuto prop k tomu, abyste do stavu pro typ trička poslali to, co uživatel vybere ve formuláři uvnitř `TShirtSetup`. Vyzkoušejte, že se stav opravdu mění a políčko pro výběr funguje.
1. Podobně propojte i další dva stavy. V komponentě `TShirtSetup` vytvořte prop `onColorChange` a `onPrintChange`. Použijte tyto props k tomu, abyste do stavu pro barvu a potisk poslali to, co uživatel vybere ve formuláři uvnitř `TShirtSetup`. Vyzkoušejte, že se stavy opravdu mění a políčka pro výběr fungují.
27 changes: 7 additions & 20 deletions daweb/react/komunikace-dite-rodic/dite-rodic.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
## Komunikace dítě → rodič

Nyní bychom chtěli zařídit, aby se uživatelem vybraný kandidát zobrazil vedle obrázku hradu. Jakmile tedy uživatel vybere nějakého kandidáta v některé z komponent `Candidate`, potřebujeme jeho jméno poslat „nahoru“ rodičovské komponentě `App`, aby si jej tato mohla uložit do stavu `president`.
Nyní bychom chtěli zařídit, aby se uživatelem vybraný kandidát zobrazil vedle obrázku hradu. Jakmile tedy uživatel vybere nějakého kandidáta v některé instance komponenty `Candidate`, potřebujeme jeho jméno poslat „nahoru“ rodičovské komponentě `HomePage`, aby si jej tato mohla uložit do stavu `president`.

Zde však narážíme na zásadní problém. Komponenta `Candidate` nemá nejmenší tušení, kdo je její rodič. Zevnitř této komponenty tato informace není nijak dostupná. Musíme si tedy pomoct malým trikem.

### Callbacky

Náš trik bude spočívat v tom, že komponentě `Candidate` skrze props předáme takzvaný <em>callback</em>. Tímto pojmem se v JavaScriptu často označuje funkce, kterou někomu předáváme proto, aby ji tento někdy později zavolal. Anglický název tohoto pojmu vzniká právě ze slovního spojení "zavolat zpátky", tedy "call back".
Náš trik bude spočívat v tom, že komponentě `Candidate` skrze _props_ předáme takzvaný _callback_. Tímto pojmem se v JavaScriptu často označuje funkce, kterou někomu předáváme proto, aby ji tento někdy později zavolal. Anglický název tohoto pojmu vzniká právě ze slovního spojení zavolat zpátky, tedy call back.

S callbacky už jsme se ve skutečnosti setkali dávno, jen jsme jim tehdy říkali posluchače událostí. Každý posluchač události je ve skutečnosti callback. Tlačítku `button` například předáváme funkci, která se má zavolat (call back) ve chvíli, kdy na tlačítko klikneme. V minulé lekci jste viděli, že v Reactu se takové věc zařídí poměrně jednoduše.

Expand All @@ -20,11 +20,11 @@ const SensitiveButton = (props) => {
};
```

### Použití callbacků ke komunikaci
## Použití callbacků ke komunikaci

V našem příkladu však callback nebudeme používat k poslouchání událostí. Budeme jej volat sami zevnitř komponenty `Candidate` ve chvíli, kdy chceme rodiči předat jméno zvoleného kandidáta.

Nejprve tedy přidáme do komponenty `Candidate` novou prop s názvem `onVote`. Abychom dali najevo, že do této prop budeme posílat funkci, volíme jméno podobně jako to známe u událostí, tedy `onClick`, `onMouseMove` apod. Jménem chceme naznačit, že tuto funkci zavoláme ve chvíli, kdy uživatel zahlasuje (anglicky :i[vote]) pro daného kandidáta.
Nejprve tedy přidáme do komponenty `Candidate` novou _prop_ s názvem `onVote`. Abychom dali najevo, že do této prop budeme posílat funkci, volíme jméno podobně jako to známe u událostí, tedy `onClick`, `onMouseMove` apod. Jménem chceme naznačit, že tuto funkci zavoláme ve chvíli, kdy uživatel zahlasuje (anglicky :i[vote]) pro daného kandidáta.

```js
const Candidate = ({ name, avatar, onVote }) => ( … )
Expand All @@ -49,19 +49,10 @@ const Candidate = ({ name, avatar, onVote }) => (
);
```

Na straně komponenty `Candidate` máme hotovo. Nyní potřebujeme vyřešit komponentu `App`. V té si vytvoříme funkci (callback), kterou budeme posílat do prop `onVote`. Pokud prop začíná slovíčkem `on`, je zvykem příslušný callback začínat slovíčkem `handle`. Náš callback se tedy bude jmenovat `handleVote` a bude mít jeden parametr `name`. To bude jméno kandidáta, na kterého uživatel kliknul.
Toto jméno nastavíme jako příslušný stav v komponentě `App`.
Na straně komponenty `Candidate` máme hotovo. Nyní potřebujeme vyřešit komponentu `HomePage`. V té potřebujeme poslat do _prop_ `onVote` nějakou funkci. My chceme při zavolání toho callbacku nastavit náš stav, pošelem proto komponentě funkci `setPresident`:

```js
const handleVote = (name) => {
setPresident(name);
};
```

Tento callback pak předáme všem komponentám `Candidate`.

```js
const App = () => {
export const HomePage = () => {
const [candidates, setCandidates] = useState([]);
const [president, setPresident] = useState(null);

Expand All @@ -76,10 +67,6 @@ const App = () => {
[]
);

const handleVote = (name) => {
setPresident(name);
};

return (
<div className="container">
<div className="castle">
Expand All @@ -99,7 +86,7 @@ const App = () => {
key={c.name}
name={c.name}
avatar={c.avatar}
onVote={handleVote}
onVote={setPresident}
/>
))}
</div>
Expand Down
6 changes: 3 additions & 3 deletions daweb/react/komunikace-dite-rodic/entry.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ sections:
- rodic-dite
- dite-rodic
- cv-komunikace
- ulozky
- dobrovolne
- cvicny-projekt
# - ulozky
# - dobrovolne
# - cvicny-projekt
16 changes: 8 additions & 8 deletions daweb/react/komunikace-dite-rodic/rodic-dite.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
## Komunikace rodič → dítě

V předchozích lekcích už jsme se naučili téměř všechno, co v Reactu potřebujeme k vývojí opravdových webových aplikací. Dostáváme se tedy do bodu, kdy postupně začneme stavět rozsáhlejší aplikace se stále větším množstvím komponent. Brzy tak narazíme na situaci, kdy si budeme potřebovat předávat informace mezi různými komponentami. Způsob, jakým si komponenty budou předávat informace bude záviset na tom, jaký spolu mají vztah. V podstatě máme tři základní možnosti.

1. Komunikace rodič → dítě
Expand All @@ -6,18 +8,16 @@ V předchozích lekcích už jsme se naučili téměř všechno, co v Reactu pot

_(Češtinářská perlička – sice v komunikaci vystupují „rodič“ a „dítě“, ale když chceme označit komponentu, neříkáme jí „dětská komponenta“ nýbrž „dceřiná komponenta“.)_

V této lekci rozebereme první dvě možnosti a třetí si necháme do další lekce. K ilustraci komunikace mezi komponentami použijeme jednoduchou webovou aplikaci, ve které si budeme hrát na prezidentské volby. Vytvořte si repozitář ze šablony [cviceni-volby](https://github.com/Czechitas-podklady-WEB/cviceni-volby). Repozitář si naklonujeme a prohlédneme si jeho strukturu.
V této lekci rozebereme první dvě možnosti a třetí si necháme do další lekce. K ilustraci komunikace mezi komponentami použijeme jednoduchou webovou aplikaci, ve které si budeme hrát na prezidentské volby. Pro tyto účely si vytvořte repozitář ze šablony [cviceni-volby](https://github.com/Czechitas-podklady-WEB/cviceni-volby). Repozitář si naklonujeme a prohlédneme si jeho strukturu.

Naše volební aplikace zobrazuje čtyři kandidáty pomocí komponenty `Candidate`. Pole obsahující jména a podobizny kandidátů najdeme ve stavu komponenty `App`. Tato data bychom normálně stáhli odněkud ze serveru. V tomto případě si život malinko ulehčíme a obsah stavu zadrátujeme přímo do kódu.
Naše volební aplikace zobrazuje čtyři kandidáty pomocí komponenty `Candidate`. Pole obsahující jména a podobizny kandidátů najdeme ve stavu komponenty `HomePage`. Tato data bychom normálně stáhli odněkud ze serveru. V tomto případě si život malinko ulehčíme a obsah stavu zadrátujeme přímo do kódu.

Z kódu můžeme vyčíst, že komponenta `App` používá komponenty `Candidate`. Budeme tedy říkat, že `App` je takzvaný rodič a komponenty `Candidate` jsou její děti.

## Komunikace rodič → dítě
Z kódu můžeme vyčíst, že komponenta `HomePage` používá komponentu `Candidate`. Budeme tedy říkat, že `HomePage` je takzvaný _rodič_ a komponenta `Candidate` je její dítě.

Předávání informací směrem od rodiče k dítěti je z našich tří situací nejjednodušší a už jsme ji dokonce mnohokrát viděli. Tato komunikace totiž probíhá předáváním hodnot skrze props.
Předávání informací směrem od rodiče k dítěti je z našich tří situací nejjednodušší a už jsme ji dokonce mnohokrát viděli. Tato komunikace totiž probíhá předáváním hodnot skrze _props_.

V našem příkladu s volbami vidíme, že komponenta `App` předává pomocí props data komponentám `Candidate`. Tuto situaci můžeme znázornit následujícím diagramem.
V našem příkladu s volbami vidíme, že komponenta `HomePage` předává pomocí _props_ data komponentám `Candidate`. Tuto situaci můžeme znázornit následujícím diagramem.

::fig{src=assets/rodic-dite.png}

Směr šipky ukazuje směr komunikace. V našem případě tečou data směrem z komponenty `App` do komponenty `Candidate` pomocí dvou props `name` a `avatar`.
Směr šipky ukazuje směr komunikace. V našem případě tečou data směrem z komponenty `HomePage` do komponenty `Candidate` pomocí dvou props `name` a `avatar`.

0 comments on commit 4cfb131

Please sign in to comment.