Do této chvíle jsem naše aplikace psali v “čistém” (anglicky se též říká “vanilla”) JavaScriptu. Postupy, které jsme se dosud naučili jsou zcela legitimní a můžeme takto psát i větší aplikace. U aplikací, které jsou velmi interaktivní a často mění obsah stránky, však narazíme na různé problémy.

  • Budeme muset náš kód zodpovědně strukturovat do komponent. S tím přichází spousta kódu, který píšeme pořád dokola.
  • Zařídit správnou komunikaci mezi velkým množstvím komponent začne být čím dál těžší.
  • Při velkém množství komponent je poměrně těžké zajistit dobrý výkon aplikace.

Na tyto problémy tvrdě narazili vývojáři Facebooku a proto vytvořili framework s názvem React, který by tyto problémy pomohl odstranit. Podobných frameworků existuje více, například Angular, Vue, Ember a další. V současné době je však React s přehledem nejpopulárnější a také nejžádanější na trhu práce.

První React aplikace

Ať už je to šikovná náhoda nebo dokonale promyšlený plán, velkou část Reactových principů už jste v tomto kurzu používali, aniž byste o tom věděli. K vytvoření našeho prvního React projektu tak stačí pouze malinko upravit konfiguraci Webpacku a naučit se psát náš kód Reactovým způsobem.

Základní Webpack projekt nastavený pro práci v Reactu si můžete stáhnout zde. Používá se stejným způsobem jako jsme u Webpack projektů zvyklí. Všimněte si však, že místo index.js zde máme soubor index.jsx. Příponu .jsx budeme používat u souborů, které obsahují Reactový kód. Co tato přípona znamená si povíme v následující části.

JavaScript XML

Do této chvíle jsme viděli dva způsoby, jak v JavaScriptu vytvořit obsah stránky. Jedna z možností byla vytvořit řetězec obsahující HTML a ten pak vložit do stránky pomocí innerHTML.

const obsah = '<h1 class="title">Moje stránka</h1>';

const appElm = document.querySelector('#app');
appElm.innerHTML = obsah;

Toto řešení je relativně přímočaré, ale má nevýhody v tom, že je těžké udělat obsah interaktivní. Naučili jsme se proto druhý způsob, kdy místo řetězce vytvoříme DOM element.

const obsah = document.createElement('h1');
obsah.className = 'title';
obsah.textContent = 'Moje stránka';

const appElm = document.querySelector('#app');
appElm.appendChild = obsah;

Toto řešení už je praktičtější, kód je však delší a méně přehledný. Zde proto s velkou famfárou a na alegorickém voze přijíždí React s třetím způsobem, jak vytvářet obsah stránky.

const obsah = <h1 className="title">Moje stránka</h1>;

Všimněte si, že do proměnné obsah přímo bez obalení uvozovkami ukládáme něco, co vypadá podezřele jako HTML. Není to však přesně HTML, nýbrž takzvané JSX (JavaScript XML). Zápis JSX je velmi podobný jazyku HTML, jsou zde však drobné rozdíly. Například místo atributu class se v JSX používá atribut className.

JSX elementy jsou Reactová obdoba DOM elementů, které jsme používali ve vanilla JavaScriptu. Jde o zcela nový typ hodnoty, a proto je můžeme stejně jako ostatní hodnoty ukládat do proměnných, předávat funkcím, vracet z funkcí, vkládat do polí i objektů a tak dále.

Pokud chceme náš JSX element vložit na stránku, musíme použít Reactovou funkci render. Tato funkce má dva parametry:

  1. JSX element, který cheme zobrazit.
  2. DOM element na stránce, do kterého chceme náš obsah vložit.
render(<h1 className="title">Moje stránka</h1>, document.getElementById('app'));

Celý soubor index.jsx tak bude vypadat takto.

import React from 'react';
import { render } from 'react-dom';
import './index.html';

render(<h1 className="title">Moje stránka</h1>, document.getElementById('app'));

Aby nám React správně fungoval, musíme importovat balíček react na začátku každého souboru, ve kterém pracujeme s JSX. Funkci render si pak importujeme z balíčku react-dom.

Obsah stránky v Reactu

V tuto chvíli se dostáváme k základnímu principu při vytváření React aplikací. Celý obsah stránky je vždy vytvořen přímo v Reactu. V souboru index.html tak už vždy budeme mít pouze element #app, do kterého zapojíme obsah vytvořený Reactem.

Mohli bychom tak chtít napsat složitější obsah stránky například takto.

import React from 'react';
import { render } from 'react-dom';
import './index.html';

render(
  <header>
    <h1>React Starter</h1>
  </header>
  <main>
    <p>Moje první React stránka</p>
  </main>
  <footer>Martin Podloucký</footer>,
  document.getElementById('app')
);

Potíž je v tom, že tento kód nám nebude fungovat. Do funkce render můžeme poslat pouze jeden JSX element, my se však pokoušíme vytvořit tři najednou. Můžeme to zachránit tak, že náš obsah obalíme do jednoho velkého divu.

render(
  <div>
    <header>
      <h1>React Starter</h1>
    </header>
    <main>
      <p>Moje první React stránka</p>
    </main>
    <footer>Martin Podloucký</footer>
  </div>,
  document.getElementById('app')
);

Tento postup však s sebou nese nevýhody. Na stránce se nám objeví zbytečný div, který může působit problémy při stylování. React proto nabízí speciální JSX element, kterému se říká fragment. Tento element vypadá jako prázdná značka, která se na výsledné stránce neobjeví. Slouží pouze k zabalení více elementů do jednoho celku. Výsledná aplikace tedy bude vypadat takto.

import React from 'react';
import { render } from 'react-dom';
import './index.html';

render(
  <>
    <header>
      <h1>React Starter</h1>
    </header>
    <main>
      <p>Moje první React stránka</p>
    </main>
    <footer>Martin Podloucký</footer>
  </>,
  document.getElementById('app')
);

Ještě bychom si obsah stránky mohli uložit do proměnné, aby nám volání funkce render nezabíralo tolik prostoru.

import React from 'react';
import { render } from 'react-dom';
import './index.html';

const appContent = (
  <>
    <header>
      <h1>React Starter</h1>
    </header>
    <main>
      <p>Moje první React stránka</p>
    </main>
    <footer>Martin Podloucký</footer>
  </>
);

render(appContent, document.getElementById('app'));

Všimněte si šikovně použitých kulatých závorek při vytváření proměnné appContent, které nám umožní mít kód hezky čitelný.

Vkládání hodnot do JSX

Velmi často budeme potřebovat do obsahu stránky zakomponovat také hodnoty uvnitř proměnných. Připomeňme si, jak bychom vložili do našeho HTML obsah proměnné ještě před Reactovými časy.

const nazev = 'Moje stránka';
const obsah = `<h1 class="title">${nazev}</h1>`;

JSX funguje velmi podobně, nepoužívá ale symbol dolaru. V Reactu budeme psát následující:

const nazev = 'Moje stránka';
const obsah = <h1 className="title">{nazev}</h1>;

Když stavíme řetězec, můžeme si obsah proměnné vložit kam chceme. JSX je však přísnější a takto velkou svobodu nemáme. Složené závorky můžeme použít pouze pro obsah elementu nebo pro hodnotu atributu. Následující kód je tedy v pořádku.

const nazev = 'Moje stránka';
const trida = 'title';
const obsah = <h1 className={trida}>{nazev}</h1>;

Nemůžeme však udělat například toto:

const nazev = 'Moje stránka';
const trida = 'title';
const znacka = 'h1';
const obsah = <{znacka} className={trida}>{nazev}</{znacka}>;

S těmito znalostmi můžeme naši výslednou stránku sestavit třeba takto.

const title = 'React Starter';
const content = 'Moje první React stránka';
const author = 'Martin Podloucký';

const appContent = (
  <>
    <header>
      <h1>{title}</h1>
    </header>
    <main>
      <p>{content}</p>
    </main>
    <footer>{author}</footer>
  </>
);

render(appContent, document.getElementById('app'));

Cvičení - první React aplikace

1

První kroky v Reactu

pohodička

Vyzkoušíme si založit jednoduchou React aplikaci s jedním index.jsx a jednoduchým CSS. Přestože v Reactu se běžně veškerý kód dělí do komponent, v tomto cvičení je ještě používat nebudeme.

  1. Z odkazu na začátku lekce si stáhněte základ pro Webpack project s Reactem. Pokračujte postupem, který už s Webpackem znáte. Nainstalujte závislosti pomocí npm install a spusťte projekt pomocí npm run start.
  2. Upravte obsah stránky ve volání funkce render. Změňte nadpis stránky h1 a v hlavičce uveďte svoje jméno.
  3. Uložte si JSX představující obsah stránky do seperátní proměnné uvnitř index.jsx a tu pak použíjte ve funkci render.
  4. Uložte si své jméno do proměnné a obsah této proměnné vložte do hlavičky stránky.
  5. Pomocí import přidejte do projektu soubor s CSS stylem, vytvořte CSS třídu intro a nastavte v ní font-style na italics. Uložte si název této třídy do proměnné a tu pak použíjte jako className pro odstavec p na vaší stránce.
2

Plyšáci

to dáš

Vytvořte v Reactu webovou stránku dle následujícího vzoru.

Stránka plyšáci

Postupujte dle následujících kroků.

  1. Založte nový React projekt dle šablony z této lekce.
  2. Upravte obsah stránky tak, aby vypadal takto.
    <h1>Plyšáci</h1>
    <div className="plushes"></div>
    
    Uložte si toto JSX do seperátní proměnné. Nezapomeňte jej správně obalit do fragmentu. Tuto proměnnou pak použíjte ve funkci render.
  3. Vytvořte si dva objekty obsahující informace o plyšácích dle následujícího vzoru.
    const plushy1 = {
      name: 'Silvestr',
      image: 'adresa obrazku',
      text: 'Silvestr rád pozoruje dění za oknem a upřímně se usmívá na všechno kolemjdoucí.',
    };
    const plushy2 = {
      name: 'Ctirad',
      image: 'adresa obrazku',
      text: 'Ctirad tráví svůj čas v blízkosti lednice a s očekáváním pozoruje její bílé dveře.',
    };
    
  4. Adresy obrázků si můžeme zkopírovat z těcho odkazů: elephant, mouse.
  5. Karta s plyšákem by měla ve výsledné stránce vypadat takto.
    <div class="plushy">
      <img class="plushy__image" src="odkaz na obrazek" />
      <h2 class="plushy__name">Jméno plyšáka</h2>
      <p class="plushy__text">Text o plyšákovi</p>
    </div>
    
    Převeďte tento kód na JSX a vložte jej do elementu .plushes, jednou pro každého plyšáka. Nezapomeňte, že v JSX se místo class píše className. Data pro obě karty vezměte z objektů plushy1 a plushy2.
  6. Přidejte do stránky soubor se styly a nastylujte ji dle zadání.

React komponenty a props

Velká výhoda, kterou nám JSX přináší, spočívá v tom, že můžeme naše komponenty psát podobně, jako na začátku, kdy jsme z komponent vraceli řetězec obsahující HTML. Připomeňme si, jak tehdy vypadala naše komponenta ShoppingItem.

const ShoppingItem = (props) => {
  return `
    <div class="item">
      <span class="item__name">${props.name}</span>
      <span class="item__amount">${props.amount}</span>
    </div>
  `;
};

V Reactu tutéž komponenty napíšeme tak, že místo řetězce bude vracet JSX element.

const ShoppingItem = (props) => {
  return (
    <div className="item">
      <span className="item__name">{props.name}</span>
      <span className="item__amount">{props.amount}</span>
    </div>
  );
};

Všimněte si důležitých rozdílů:

  1. Nepoužíváme už zpětné apostrofy. Místo toho celé JSX uzavřeme do závorek, aby se nám kód hezky četl.
  2. Pokud chceme dovnitř JSX zakomponenovat obsah nějaké proměnné, místo ${promenna} píšeme prostě {promenna}. Proti předchozímu zápisu nám tak zmizí znak dolaru.

Ta nejhezčí věc na Reactu je však způsob, jakým naši komponentu zapojíme do zbytku stránky. Místo toho, abychom složitě používali innerHTML nebo appendChild, můžeme se tvářít, že naše komponenta je obyčejný tag a props jí předat pomocí atributů. Použití komponenty ShoppingItem by pak mohlo vypadat takto.

import React from 'react';
import { render } from 'react-dom';
import './index.html';

const ShoppingItem = (props) => {
  return (
    <div className="item">
      <span className="item__name">{props.name}</span>
      <span className="item__amount">{props.amount}</span>
    </div>
  );
};

render(
  <>
    <header>
      <h1>Shopping List</h1>
    </header>
    <main className="shopping-list">
      <ShoppingItem name="Jablka" amount="1 kg" />
      <ShoppingItem name="Skořice" amount="1 balení" />
      <ShoppingItem name="Máslo" amount="250 g" />
      <ShoppingItem name="Mouka" amount="500 g" />
    </main>
    <footer>Martin Podloucký</footer>
  </>,
  document.getElementById('app')
);

React se za nás postará a veškerou špinavou práci, kdy hodnoty atributů zabalí do jednoho objektu, pošle jej funkci ShoppingItem a výsledek zapojí do naší stránky.

Doporučené postupy

Framework React vznikl ve společnosti Facebook mezi roky 2011 až 2013. Má tedy za sebou již několik let používání a za tu dobu se ustálily určité doporočené postupy, jak psát React aplikace. Některé z nich zmíníme již takto na začátku, abychom co nejdříve působili jako profesionálové.

Hlavní komponenta

V Reactu není příliš zvykem psát do funkce render příliš obsáhly kód. Většinou postupujeme tak, že celá naše aplikace je jedna velká komponenta, která pak skládá dohromady další námi napsané komponenty. Této komponentě většinou dáváme název App. Kód nákupního seznamu by pak vypadal takto.

import React from 'react';
import { render } from 'react-dom';
import './index.html';

const ShoppingItem = (props) => {
  return (
    <div className="item">
      <span className="item__name">{props.name}</span>
      <span className="item__amount">{props.amount}</span>
    </div>
  );
};

const App = () => {
  return (
    <>
      <header>
        <h1>Shopping List</h1>
      </header>
      <main className="shopping-list">
        <ShoppingItem name="Jablka" amount="1 kg" />
        <ShoppingItem name="Skořice" amount="1 balení" />
        <ShoppingItem name="Máslo" amount="250 g" />
        <ShoppingItem name="Mouka" amount="500 g" />
      </main>
      <footer>Martin Podloucký</footer>
    </>
  );
};

render(<App />, document.getElementById('app'));

Rozdělení komponent do složek

Už při práci v čistém JavaScriptu jsme se učili rozdělovat komponenty do separátních složek. Tento postup budeme v Reactu přísně dodržovat a pro každou komponenty vždy vytvoříme složku obsahující její zdrojový JavaScript, styly i obrázky.

Naší komponentu ShoppingItem tak vložíme do složky ShoppingItem se souborem index.jsx. Ten bude obsahovat kód naší komponenty.

import React from 'react';

const ShoppingItem = (props) => {
  return (
    <div className="item">
      <span className="item__name">{props.name}</span>
      <span className="item__amount">{props.amount}</span>
    </div>
  );
};

export default ShoppingItem;

Všimněte si, že zde neimportujeme funkci render. Tu použijeme pouze v hlavním index.jsx na zobrazení celé aplikace. V jednotlivých komponentách ji nepotřebujeme. Také dejte pozor na to, že komponentu exportujeme pomocí export default. To je speciální forma exportování pro případ, kdy z našeho souboru chceme exportovat pouze jednu funkci.

Pokud bychom komponentu exportovali tak, jako dříve

export const ShoppingItem = (props) => {

importovali bychom ji pak takto

import { ShoppingItem } from './ShoppingItem';

Pokud ji exportujeme pomocí export default, při importu vynecháme složené závorky.

import ShoppingItem from './ShoppingItem';

Výsledný hlavní index.jsx celé aplikace pak bude vypadat takto.

import React from 'react';
import { render } from 'react-dom';
import ShoppingItem from './ShoppingItem';
import './index.html';

const App = () => {
  return (
    <>
      <header>
        <h1>Shopping List</h1>
      </header>
      <main className="shopping-list">
        <ShoppingItem name="Jablka" amount="1 kg" />
        <ShoppingItem name="Skořice" amount="1 balení" />
        <ShoppingItem name="Máslo" amount="250 g" />
        <ShoppingItem name="Mouka" amount="500 g" />
      </main>
      <footer>Martin Podloucký</footer>
    </>
  );
};

render(<App />, document.getElementById('app'));

Cvičení - React komponenty

3

Aplikace

pohodička
  1. Z odkazu na začátku lekce si stáhněte základ pro Webpack project s Reactem, nainstalujte závislostí pomocí a spusťte projekt.
  2. V souboru index.jsx vytvořte komponentu App, která nebude mít žádné props. Přesuňte do ní obsah, který je původně přímo ve volání funkce render.
  3. Do volání funkce render pošlete JSX obsahující pouze komponentu App.
  4. Vytvořte komponentu Header, která bude obsahovat kód pro hlavičku stránky. Jediná její prop bude title udávající obsah elementu h1. Vytvořte pro komponentu speciální složku a správně ji exportujte. V hlavním souboru index.jsx komponentu importujte a použijte ji uvnitř komponenty App.
  5. Následujte stejný postup jako výše a vytvořte komponentu Footer, která bude představovat patičku stránky. Tato komponenta bude mít také jednu prop s názvem author, která udává jméno autora stránky.
  6. Do třetice vytvořte komponentu Main, která bude představovat hlavní obsah stránky. Tato komponenta bude mít opět jednu prop s názvem content, která bude udávat obsah odstavce.
4

Datumy

to dáš
  1. Z odkazu na začátku lekce si stáhněte základ pro Webpack project s Reactem, nainstalujte závislostí pomocí a spusťte projekt.

  2. Vytvořte komponentu Today, která bude očekávat tři props:

    • day - řetězec s číslem dne, například '07',
    • month - řetězec s číslem měsíce, například '12',
    • year - řetězec s číslem roku, například '2020'.

    Tato komponenta by měla zobrazit datum ve formátu 07.12.2020. Zabalte každou položku datumu do zvláštního span elementu a dejte každé vlastní CSS třídu, abychom mohli den měsíc i rok nastylovat zvlášť.

  3. Vytvořte komponentu App, která na stránce zobrazí tři různé datumy pomocí Today.

  4. Pro komponentu Today vytvořte soubor se styly a nastylujte číslo pro den tak, aby bylo zobrazeno tučně a číslo pro rok tak, aby bylo zobrazeno o 20% menším fontem.