Skip to content

Commit

Permalink
Doplnění materiálů pro bonusové lekce – TypeScript a Backend.
Browse files Browse the repository at this point in the history
  • Loading branch information
FilipJirsak committed May 28, 2024
1 parent 2de46dd commit 13b4f57
Show file tree
Hide file tree
Showing 12 changed files with 503 additions and 0 deletions.
5 changes: 5 additions & 0 deletions daweb/bonus/backend/entry.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
title: Úvod do backendu
lead: Jak si napsat jednoduchý backend pomocí Deno
access: claim
sections:
- ukazkovy-projekt
3 changes: 3 additions & 0 deletions daweb/bonus/backend/ukazkovy-projekt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## Ukázkový projekt

Celá lekce se točí kolem ukázkového projektu, který najdete na GitHubu: [priklad-projekty](https://github.com/FilipJirsak-Czechitas/priklad-projekty). Popis použití je v `README` uvedeného projektu.
5 changes: 5 additions & 0 deletions daweb/bonus/entry.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
title: Bonusy
lead: Volitelné lekce nad rámec témat akademie, ve kterých se můžete dozvědět něco navíc.
lessons:
- backend
- typescript
98 changes: 98 additions & 0 deletions daweb/bonus/typescript/api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
## API v Typescriptu

Dostáváme se do závěrečné fáze naší malé aplikace. Máme komponentu `Form`, která sbírá data od uživatele a máme komponentu `Activity`, která nám zobrazí vygenerovanou aktivitu. Nezbývá než vše dát dohromady a vytvořit funkci pro vygenerování activity. Proto si ukážeme, jak používat api volání v typescritpu.

Vytvoříme si asynchronní funkci `fetchData`, která na vstupu bude očekávat informaci, o jakou aktivitu má uživatel zájem. Tuto informaci pak předáme v metodě fetch v url adrese. Funkce by nám na základě typu, měla vrátit jednu náhodnou aktivitu.

```js
const fetchData = async (type: string) => {
const res = await fetch(`http://www.boredapi.com/api/activity?type=${type}`);
const data = await res.json();
console.log(data);
};
```

Takto získaná data musíme uložit do stavu, abychom s nimi mohli dál pracovat. Ovšem jakého budou datového typu? V reálném životě byste dostali strukturu dat od svých Backend kolegů, ale pro náš případ bude stačit, když se podíváme do konzole, co nám naše funkce `fetchData` vrátí. Vidíme, že je to objekt tvořený několika vlastnostmi, takže si stačí podle nich vytvořit interface.

```js
interface ActivityDataStructure {
accessibility: number
activity: string;
key: string;
link: string;
participants: number;
price: number;
type: string;
}
...
const [activityData, setActivityData] = useState<ActivityDataStructure>();
```

Upravíme naši funkci `fetchData`, aby ukládala data do stavu.

```js
const fetchData = async (type: string) => {
const res = await fetch(`http://www.boredapi.com/api/activity?type=${type}`);
const data = await res.json();
setActivityData(data);
};
```

Zbývají poslední dvě věci a to vytvořit si funkci, která z formuláře obdrží data od uživatele a odešleje pomocí Fetche. A pak už jen musíme zobrazit data, které obdržíme v odpověďi našeho volání.

```js
const handleSubmitForm = (data: FormDataStructure) => {
fetchData(data.type);
};
```

Výsledný kód v souboru `App.tsx` pak bude vypadat takto:

```js
import { useState } from 'react';
import { Activity } from './components/activity';
import { Form, FormDataStructure } from './components/form';
import './App.css';

interface ActivityDataStructure {
accessibility: number
activity: string;
key: string;
link: string;
participants: number;
price: number;
type: string;
}

function App() {
const [activityData, setActivityData] = useState<ActivityDataStructure>();

const fetchData = async (type: string) => {
const res = await fetch(`http://www.boredapi.com/api/activity?type=${type}`);
const data = await res.json();
setActivityData(data);
}

const handleSubmitForm = (data: FormDataStructure) => {
fetchData(data.type);
};

return (
<>
<Form
onSubmitForm={handleSubmitForm}
/>
{activityData && (
<Activity
nameOfActivity={activityData.activity}
type={activityData.type}
participants={activityData.participants}
price={activityData.price}
/>
)}
</>
)
}

export default App
```
3 changes: 3 additions & 0 deletions daweb/bonus/typescript/cv-typescript.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## Cvičení: Vyzkoušej si Typescript

::exc[cvlekce/typescript]
9 changes: 9 additions & 0 deletions daweb/bonus/typescript/cvlekce/typescript.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
title: Jokes generator
demand: 3
---

1. Stáhni si [vzorový projekt](https://github.com/Czechitas-podklady-WEB/jokes-demo-app) v Reactu. Nainstaluj závislosti a projekt si spusť. Podívej se jak vypadá v prohlížeči a jaký je jeho kód.
2. Pomocí vite a jeho šablony react-ts si vytvoř vlastní projekt. Tvým úkolem je naprogramovat stejnou aplikaci ovšem s použitím Typescriptu.
3. Můžeš kopírovat libovolný kód z původní aplikace, ulehčí ti to práci. Stejně tak si můžeš zkopírovat použité styly, ale neboj se zapojit i vlastní fantazii.
4. Pokud by tě napadlo jakékoli vylepšení, s chutí do něj a nezapomeň se pochlubit se svým výtvorem ostatním.
10 changes: 10 additions & 0 deletions daweb/bonus/typescript/entry.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
title: Úvod do Typescriptu
lead: Co je to Typescript a jak ho v Reactu používat
access: claim
sections:
- uvod-do-typescriptu
- typescript-v-reactu
- komponenty-a-props
- formulare-a-predavani-dat
- api
- cv-typescript
146 changes: 146 additions & 0 deletions daweb/bonus/typescript/formulare-a-predavani-dat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
## Formuláře a předávání dat mezi komponentami

V naší aplikaci budeme chtít aby si uživatel nechal vygenerovat vhodnou volnočasovou aktivitu na základě jeho preferencí. Pro začátek nám bude stačit, když ho necháme vybrat si, o jaký typ aktivity by měl zájem. A aby jsme mohli tuto informaci získat, musíme si na to vytvořit formulář, který bude uživatel vyplňovat.

Vytvoříme si novou složku `Form`, kde si v `index.tsx` vytvoříme komponentu `Form`, která bude vracet jsx ve formátu:

```js
<form onSubmit={() => {}}>
<label>
<p>Your Name: </p>
<input name="name" />
</label>
<label>
<p>Select type of Activities: </p>
<select name="type">
<option value=""></option>
<option value="education">Education</option>
<option value="relaxation">Relaxation</option>
</select>
</label>
<button type="submit">Submit</button>
</form>
```

Komponenta má jediný úkol. Bude předávat vstup od uživatele do nadřazené komponenty. V jejím inteface bude tedy jediná props, která bude očekávat callback funkci, prostřednictvím, které předá data ven.

```js
interface FormProps {
onSubmitForm: () => void;
}

export const Form: React.FC<FormProps> = ({ onSubmitForm }) => {
return <form onSubmit={onSubmitForm}>...</form>;
};
```

Od uživatele dostaneme dva údaje, jeho jméno a preferovaný typ aktivity. Budete tedy potřebovat stav, do kterého tyto údaje uložíme a bude potřeba aby jsme určili, jakého datového typu tyto data jsou. Opět k tomu použijeme interface.

```js
interface FormDataStructure {
name: string;
type: string;
}

export const Form: React.FC<FormProps> = ({
onSubmitForm
}) => {
const [formData, setFormData] = useState<FormDataStructure>({
name: '',
type: ''
});
...
}
```

Vytvoříme si funkci `handleChange`, která nám bude poslouchat změny na formuláři, které provede uživatel a bude je ukládat do stavu. Taková funkce očekává vstup, který by měl být typu `event`, ale jaký přesně typ to je? S tím nám poradí vlastnost `onChange` u inputu. Stačí, když na ní najedem myší a typescript nám správný datový typ prozradí.

```js
<input
name="name"
onChange={(e) => {
console.log(e);
}}
// (parameter) e: React.ChangeEvent<HTMLInputElement>
/>
```

Teď už víme, jaký datový typ potřebujeme a naše funkce `handleChange` bude vypadat takto:

```js
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setFormData({
...formData,
[e.target.name]: e.target.value,
});
};
```

Ovšem ve formuláři máme ještě jiný element a to je `<select>`. Když se budeme snažit použít stejnou funkci i na něj, Typescript se bude zlobit a řekne nám, že datový typ `ChangeEvent<HTMLSelectElement>`, který má element `<select>` neodpovídá datovému typu `ChangeEvent<HTMLInputElement>`, který očekává naše funkce `handleChange` jako vstup. V takovém případě nám nezbývá nic jiného než říci, že vstup u naší funkce, může být jeden nebo druhý datový typ. V řeči Typescriptu se jedná o Union types. Jednotlivé typy od sebe oddělujeme vertikální čárou `|`.

```js
const handleChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>
) => {
setFormData({
...formData,
[e.target.name]: e.target.value,
});
};
```

Teď už nám zbývá jen při odeslání formuláře předat data od uživatele ven z komponenty. Budeme tedy potřebovat funkci `handleSubmit`, která se o to postará. Protože budeme předávat do callback funkce stav `formData`, potřebujeme také upravit interface tak, aby props `onSubmitForm` očekávala vstup ve správném datovém typu.

Výsledná komponenta `Form` bude vypadat takto:

```js
import { useState } from "react";

interface FormProps {
onSubmitForm: (data: FormDataStructure) => void;
}

interface FormDataStructure {
name: string;
type: string;
}

export const Form: React.FC<FormProps> = ({ onSubmitForm }) => {
const [formData, setFormData] = useState<FormDataStructure>({
name: "",
type: "",
})

const handleChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>
) => {
setFormData({
...formData,
[e.target.name]: e.target.value,
});
};

const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
onSubmitForm(formData);
};

return (
<form onSubmit={handleSubmit}>
<label>
<p>Your Name: </p>
<input name="name" onChange={handleChange} />
</label>
<label>
<p>Select type of Activities: </p>
<select name="type" onChange={handleChange}>
<option value=""></option>
<option value="education">Education</option>
<option value="relaxation">Relaxation</option>
</select>
</label>
<button type="submit">Submit</button>
</form>
);
};
```
90 changes: 90 additions & 0 deletions daweb/bonus/typescript/komponenty-a-props.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
## Komponenty a jejich props

Představte si, že máte volný večer a nevíte, jakou ativitou ho vyplnit. Vytvoříme si proto aplikaci, která nám na základě vstupů od uživatele vrátí seznam možných aktivit, kterým bychom se mohli věnovat.

Naši aplikaci si vybudujeme od těch nejjednodušších částí a proto si jako první vytvoříme komponentu, která nám bude návrhy na možné aktivity zobrazovat.

V našem projektu si ve složce `src` vytvoříme složku `components` a v ní složku pro naši první komponentu v Typescriptu, kterou si pojmenujeme `Activity` a vytvoříme si v ní soubor `index.tsx`.
Protože používáme Typescript, tak naše soubory končí na `tsx` místo `jsx` a stejně tak soubory, které dříve používali čistý Javascript, tedy končily na `js`, budou v Typescriptu končit na `ts`.

V `index.tsx` bude následující kód:

```js
export const Activity = () => (
<div>
<h3>Name of the Activity: </h3>
<p>Type: </p>
<p>Participants: </p>
<p>Price: </p>
</div>
);
```

Každá komponenta v Typescriptu by měla mít definovaný svůj typ. My používáme funkční komponenty, takže naše komponenta bude mít typ `FunctionComponent` nebo zkráceně `FC` a jsme v Reactu, takže naše komponenta bude vypadat takto:

```js
export const Activity: React.FC = () => (
...
);
```

Naše komponenta bude také očekávat nějaké vstupy, tedy props, a i ty musíme definovat. V Typescriptu se props u komponent definují pomocí `interface`, který se následně předává komponentě jako tzv. generický parametr. Ten se uvádí za definici typu komponenty mezi `<>`.

```js
interface ActivityProps {
nameOfActivity: string;
type: string;
participants: number;
price: number;
}

export const Activity: React.FC<ActivityProps> = ({
nameOfActivity,
type,
participants,
price,
}) => (
<div>
<h3>Name of the Activity: {nameOfActivity}</h3>
<p>Type:{type} </p>
<p>Participants: {participants}</p>
<p>Price: {price}</p>
</div>
);
```

Takto vytvořenou komponentu si naimportujeme do souboru `App.tsx`. Všimněte si, že nám ji Typescript červeně podtrhne a vyhodí chybu:

```js
import { Activity } from "./components/activity";

function App() {
return (
<>
<Activity /> // Error: Type '{}' is missing the following properties from
type 'ActivityProps': nameOfActivity, type, participants, price ts(2739)
</>
);
}

export default App;
```

Typescript nám říká, že komponenta vyžaduje vstupy, které jsou `nameOfActivity`, `type`, `participants` a `price`. Je tedy nutné tyto props u komponenty uvést a vložit do nich vstupy se správným datovým typem. Typescript nám tak napovídá, co komponenta potřebuje a zároveň nás hlídá, zda jí předáváme správné údaje. Použití naší komponenty by mělo vypadat nějak takto:

```js
function App() {
return (
<>
<Activity
nameOfActivity="Learn React II."
type="education"
participants={40}
price={1}
/>
</>
);
}
```

Teď už umíme používat Typescript v jednoduchých komponenách a v další lekci si ukážeme jak pracovat s Typescriptem, pokud očekáváme nějaký vstup od uživatele a jak tento vstup předávat mezi komponentami.
13 changes: 13 additions & 0 deletions daweb/bonus/typescript/typescript-v-reactu.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
## Typescript v Reactu

V předchozí sekci jsme si řekli, proč Typescript používat a jaké základní typy máme. Dost bylo teorie a teď si ukážeme, jak se Typescript používá v praxi.

Vytvoříme si novou složku, kde budeme mít náš testovací projekt. Založíme si zde reaktí aplikaci, kterou si založíme pomocí vite. Podívejte se na průvodce na stránce [vitejs.dev](https://vitejs.dev/guide/#scaffolding-your-first-vite-project), kde si můžete všimnou řady předpřipravených šablon, z nichž si vybereme šablonu `react-ts`. Náš instalační script bude vypadat takto:

```js
npm create vite my-app -- --template react-ts
```

Vite nám sestaví základní kostru projektu a taktéž za nás nastaví Typescript. V aplikaci si můžete všimnout souboru `tsconfig.json`. Jedná se o klíčový soubor, protože obsahuje konfiguraci Typescriptu. Tímto souborem říkáme Typescriptu, jak se má v našem projektu chovat a to vůči vstupním souborům, jsx kódu, modulům, které můžeme instalovat až po výstupní soubory.

Nastavování `tsconfig.json` se ovšem věnovat nebudeme. Podrobné informace naleznete na stránkách [typescriptlang.org](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html). Všechno potřebné pro náš projekt už za nás nastavil vite.
Loading

0 comments on commit 13b4f57

Please sign in to comment.