C# týden November Black Friday
Black Friday je tu! Využij jedinečnou příležitost a získej až 80 % znalostí navíc zdarma! Více zde
Pouze tento týden sleva až 80 % na e-learning týkající se C#

Lekce 3 - Komponenty React kalkulačky

Unicorn College Tento obsah je dostupný zdarma v rámci projektu IT lidem.
Vydávání, hosting a aktualizace umožňují jeho sponzoři.

V minulé lekci, První aplikace v React, jsme započali tvorbu jednoduché kalkulačky pomocí knihovny React. V dnešním tutoriálu na ni navážeme a dokončíme ji. Minule jsme skončili u základní struktury našich komponent, dnes navážeme doplněním jejich vlastností i stavů.

Komponenty

Začneme konceptem vlastností (properties), které se používají pro konfiguraci a předávání dat do komponent.

Vlastnosti

Jednoduše napíšeme v rámci JSX ke komponentě nějaký atribut, např. x="5", a tato komponenta ho poté uvnitř dostane k dispozici přes this.props, tj. this.props.x zkrátka bude 5. Pojďme si to ukázat na příkladu.

src/calculator/Re­sult.js

Použití vlastnosti se krásně hodí pro naši komponentu zobrazující výsledek. Té jako parametr předáme aktuální hodnotu, kterou má zobrazit:

import React, { Component } from 'react';

export default class Result extends Component {
    render() {
        const result = this.props.value;
        if (result || result === 0) return <div className="Result">Výsledek je: {result}</div>;
        else return null;
    }
}

V tomto kódu se děje hned několik věcí. Předáváme hodnotu zobrazovaného výsledku pomocí vlastnosti value a ukládáme ji do lokální konstanty result. S tou potom pracujeme a podle její hodnoty kontrolujeme, zda máme zobrazit náš výsledek či nikoliv.

Dobré je poukázat na to, že pokud komponenta němá nic vykreslit, tak by měla vracet null.

Dále si můžeme zkusit vlastnost použít. Jednoduše uvnitř komponenty naší aplikace nastavme např.: <Result value="5" /> a hned bychom měli vidět výsledek ve spuštěné aplikaci :)

Stav

Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

Stav (state) je podobný vlastnostem, ale používá se pouze uvnitř komponenty pro řízení jejího datového toku. V podstatě se jedná o privátní data komponenty pouze pro vnitřní použití. Pojďme si to opět ukázat na příkladu.

src/calculator/Num­berInput.js

Přidáme si definici stavu do naší komponenty pro číselný vstup tak, aby v něm byla uložená hodnota vstupního pole:

import React, { Component } from 'react';

export default class NumberInput extends Component {
    constructor(props) {
        super(props);
        this.state = { value: this.props.value };
    }

    render() {
        const { name, label } = this.props;

        return (
            <label htmlFor={name}>
                {label}
                <input id={name} type="number" name={name} required
                    value={this.state.value} />
            </label>
        );
    }
}

Jak vidíte, stav se obvykle definuje i inicializuje v konstruktoru a je uložený jako JS objekt s klíči a jejich hodnotami. Samozřejmě zde nesmíme opomenout, že dědíme ze React třídy Component, která ve svém konstruktoru potřebuje předání svých vlastností.

Co se potom týká vykreslování komponenty, tak nejdříve jsme sem rovnou přidali i její vlastnosti jako název (name) a popisek (label). Pokud máte jako v tomto případě více vlastností, není špatné pro jednoduchost použít při jejich extrakci z this.props JS dekonstrukci objektů z ES6+ :)

Nakonec zde definujeme použití našeho stavu pro hodnotu samotného <input>u. Možná se teď ptáte, proč jsme tam stav přidali tímto způsobem, když vlastně momentálně neděláme nic jiného, než že mezi-ukládáme hodnotu z vlastnosti?! To je proto, že náš stav teprve využijeme při aktualizaci hodnoty v <input>u, na což se teď hned podíváme.

Zpracování událostí

Doposud jsme v naší aplikaci tak trochu opomíjeli jeden zásadní faktor a tím je uživatelská interakce. Naše aplikace se totiž většinou dá do pohybu právě díky tomu, že uživatel na něco klikl apod. A jak řešíme tyto věci v rámci JS? Ano, správně, pomocí událostí (event) a jejich zpracování. To se při použití Reactu v podstatě nemění, pouze budeme chtít, aby příslušná událost aktualizovala také náš stav. Pojďme si teď trochu rozšířit předchozí příklad.

src/calculator/Num­berInput.js

Přidáme si do naší komponenty událost, která prováže její stav přímo s hodnotou v <input>u:

import React, { Component } from 'react';

export default class NumberInput extends Component {
    constructor(props) {
        super(props);
        this.state = { value: this.props.value };
        this.handleChange = this.handleChange.bind(this);
    }

    handleChange(event) {
        const value = event.target.value;
        this.setState({ value });
        this.props.onChange(Number(value));
    }

    render() {
        const { name, label } = this.props;

        return (
            <label htmlFor={name}>
                {label}
                <input id={name} type="number" name={name} required
                    value={this.state.value}
                    onChange={this.handleChange} />
            </label>
        );
    }
}

Paráda, podařilo se nám synchronizovat náš stav s hodnotou v <input>u. Tedy když teď do něj něco napíšeme, dojde k zavolání metody handleChange() a následné aktualizaci vnitřního stavu komponenty. Dále je zde ale ještě pár další technických drobností, které je potřeba zmínit.

Nejdříve samotná definice metody handleChange(). Asi jste si všimli, že zde přibyl i její bind() v rámci konstruktoru. To je proto, že JS má obecně problém s předáváním kontextu this a v rámci použití JSX se to bohužel projeví. Tímto tedy sjednáme nápravu.

Možná někoho napadne, že bychom místo klasických funkcí mohli použít tzv. "arrow functions", které tenhle problém nemají. To bude fungovat a můžete to tak udělat, ale potom bude jejich definice přímo uvnitř JSX a tak se při každém překreslení komponenty definuje nová funkce, což není často úplně optimální řešení, obzvlášť když je daná funkce složitější.

Dále je zde samotná definice funkce handleChange(event). Zde vidíme klasické zpracování události pro vytažení hodnoty <input>u. Následuje nastavení stavu, které bychom měli zásadně provádět pomocí metody this.setState(), nikoliv přímým přiřazením. Tato metoda totiž zároveň zajistí případné překreslení komponenty.

Nakonec zde propagujeme svůj stav do vnějšího světa. Jak už jsme si vysvětlili, stav je pouze pro naši vnitřní potřebu, takže pokud ho chceme projevit i navenek, zařídíme to jeho propagací pomocí vlastností. V našem případě tedy pouze propagujeme událost do naší vlastnosti this.props.onChange s drobným vylepšením převodu na číslo. Tedy ten, kdo náš program bude používat, dostane vždy číselnou hodnotu (nebo NaN), tak jak bychom asi od číselného <input>u očekávali :)

src/calculator/Cal­culatorForm.js

Pro správnou funkčnost obsluhy zadání vstupu je třeba ještě definovat obslužnou metodu v rodičovské komponentě CalculatorForm. V konstruktoru definujeme obecnou obsluhu handleChange a poté nabindujeme konkrétní obslužné metody handleChangeX a handleChangeY pro oba číselné vstupy. Tyto metody poté předáme právě v atributu onChange instancím komponenty NumberInput. Rodičovská komponenta bude mít nyní následující kód:

export default class CalculatorForm extends Component {
    constructor(props) {
        super(props);
        this.state = { x: 0, y: 0, operation: null, result: null };

        const handleChange = (name, value) => this.setState({ [name]: value });
        this.handleChangeX = handleChange.bind(this, 'x');
        this.handleChangeY = handleChange.bind(this, 'y');
    }

    render() {
        return (
            <form className="CalculatorForm">
                <NumberInput name="x"
                             value={this.state.x}
                             onChange={this.handleChangeX} />
                <NumberInput name="y"
                             value={this.state.y}
                             onChange={this.handleChangeY} />
                <OperationSelect />
                <input type="submit" value="Spočítej" />
            </form>
        );
    }
}

V příští lekci, Dokončení React kalkulačky, se podíváme na další komponenty a naši kalkulačku v React tím dokončíme.


 

 

Článek pro vás napsal Jindřich Máca
Avatar
Jak se ti líbí článek?
2 hlasů
Autor se věnuje převážně webovým technologiím, ale má velkou zálibu ve všem vědeckém, nejen ze světa IT. :-)
Předchozí článek
První aplikace v React
Všechny články v sekci
React
Miniatura
Následující článek
Dokončení React kalkulačky
Aktivity (4)

 

 

Komentáře

Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zatím nikdo nevložil komentář - buď první!