Lekce 3. - React - State a Props

25.02.2021 Programování #react #programování

Další lekce výuky Reactu se zaměřením na Stavy (State) Vlastnosti (Prosp).


Práce s daty

Při vytváření aplikace React se neobejdeme bez nutnosti přijímat anebo předávat data komponentám. Může se jednat o podřízenou komponentu přijímající data od svého rodiče nebo možný uživatel přímo zadává data do komponenty.

Pochopení toho, jak toky dat mezi komponentami probíhají, je velmi důležité pro jejich sestavení v Reactu. To nás přivádí k novým pojmů - Stavy (State) a Vlastnosti (Props).

Začínáme s vlastnostmi (Props)

Vlastnosti (Props) jsou jedním ze dvou typů „modelových“ dat v Reactu. Lze je považovat za atributy v prvku HTML. Například atributy - typechecked- ve tagu input.

<input type="checkbox" checked="{true}" />

Jsou primárním způsobem, jak odesílat data nebo obslužné rutiny událostí směrem dolů do stromu komponent. tj. od rodiče k jeho podřízené složce.

Když k tomu dojde, data, která jsou přijata v podřízené komponentě, se stanou jen pro čtení a nemohou být podřízenou komponentou změněna. Důvodem je, že data jsou vlastněna nadřazenou komponentou a lze je změnit pouze stejnou nadřazenou komponentou.

Rychlé příklady pro práci s vlastnostmi (Props)

Komponenta přijme argument jako objekt props:

Předávání dat z jedné komponenty do druhé jako parametry.

Pokud máme proměnnou, kterou chceme odeslat, a ne řetězec jako v příkladu výše, vložme název proměnné do složených závorek:

Objekt jako parametr:

Vlastnosti v konstruktoru. Pokud má komponenta funkci konstruktoru, vlastnosti by měly být vždy předány konstruktoru a také metodě pomocí React.Component super().

Stav (State)

Na rozdíl od vlastností jsou údaje o stavu lokální a specifické pro komponentu, která je vlastní. Nejsou přístupný žádným dalším komponentám, pokud se komponenta vlastníka nerozhodne předat ji jako vlastnosti svým podřízeným komponentám.

I když podřízená komponenta přijímá data ve svých vlastnostech, neví, odkud přesně data pocházejí.

Tímto způsobem by součást přijímače nevěděla, jak aktualizovat data, pokud neodkazuje na nadřazeného vlastníka.

Většinou se ocitneme v deklaraci stavu, kdykoli chceme, aby byla některá data aktualizována, kdykoli uživatel provede nějakou akci, jako je aktualizace vstupního pole, přepínání tlačítka nabídky atd. Také v případě, že dvě nebo více podřízených komponent musí spolu komunikovat.

Rychlé příklady na práci se stavy (State)

Objekt stavu je iniciován v konstruktoru:

Objekt může obsahovat libovolný počet vlastností:

Na objekt state se lze odkazovat v komponentě kdekoliv pomocí syntaxe: this.state.propertyname

Změna objektu state. Chceme-li změnit hodnotu v objektu stavu, použijeme metodu this.setState().

Když se hodnota v objektu state změní, komponenta se znovu vykreslí, což znamená, že se výstup změní podle nové hodnoty.

Vždy použijte ke změně stavu objektu metodu setState(), která zajistí, že komponenta bude vědět, že byla aktualizována a zavolá metodu render() (a všechny ostatní metody životního cyklu).

Přidávání stavu v aplikaci To-Do

Podle návrhu aplikace, komponenta InputTodo přebírá odpovědnost za přijetí vstupu uživatele. Jakmile komponenta přijme tato vstupní data, musíme je předat do centrálního umístění, kde je můžeme spravovat a zobrazit v zobrazení prohlížeče.

To umožňuje ostatním komponentám přístup k těmto datům.

Například komponenta TodosList bude přistupovat k datům a zobrazovat své položky úkolů. Komponenta TodoItem (která je držitelem příslušného políčka a tlačítka Delete) bude přistupovat k datům pro aktualizaci tohoto políčka, bude upravovat položky, a také odstraňovat položky ze strany stavu.

Nyní pro každou podřízenou komponentu, která bude přistupovat k datům, budeme muset deklarovat sdílený stav v jejich nejbližším společném nadřazeném prvku. Z tohoto důvodu budou sdílená data stavu žít v komponentě TodoContainer, což je jejich nejbližší společný rodič. Tato nadřazená komponenta pak může předat stav zpět dětem pomocí vlastností props. To je to, čemu se říká „Zvedání stavu nahoru“ a následný tok dat „shora dolů“.

Místo deklarování sdíleného stavu v nadřazené komponentě, jak je uvedeno výše, je alternativou ke správě údajů o stavu použití rozhraní Context API. V této sérii lekcí začneme nejjednodušší z nich. Jakmile budeme mít základní znalosti, můžeme se naučit používat rozhraní Context API pro správu stavu.

Chceme-li přidat stav do komponenty třídy, jednoduše vytvoříme objekt state s párem klíč – hodnota. Hodnota může být jakéhokoli datového typu. V níže uvedeném kódu je hodnotou pole.

state = {
  todos: [],
}

Pokud se na náš design podíváte kriticky, aktualizujeme zaškrtávací políčko úkolů. A jak možná víte ze základního HTML, používá vlastnost checked (což je booleovský atribut).

Z toho vyplývá, že k tomu musíme učinit opatření. Takže typický úkol bude vypadat takto:

{
  id: 1,
  title: "Setup development environment",
  completed: true
}

Klíč id velmi důležité, jak se dozvíme dále.

V naší aplikaci pro začátek zobrazíme na obrazovce výchozí položky. Nyní místo prázdného pole budeme mít řadu objektů. Přidejme tedy následující kód těsně nad metodu render() v souboru TodoContainer.js:

state = {
 todos: [
   {
     id: 1,
     title: "Setup development environment",
     completed: true
   },
   {
     id: 2,
     title: "Develop website and add content",
     completed: false
   },
   {
     id: 3,
     title: "Deploy to live server",
     completed: false
   }
 ]
};

Ve stejném souboru aktualizujme metodu render() tak, aby vypadala takto:

render() {
  return (
    <ul>
      {this.state.todos.map(todo => (
         <li>{todo.title}</li>      
       ))}    
    </ul>
  );
}

Uložte soubor a zkontrolujte rozhraní.

přidání údajů o stavu

Co jsme udělali?

Poté, co jsme definovali data todos v objektu state, jsme k nim přistoupili v metodě render() pomocí this.state.todos.

Kromě metody render() se jedná o jednu z metod životního cyklu (více o tom později), které se vykonává během fáze Render. V této fázi se React rozhodne, jaké změny je třeba v DOMu provést.

Vzhledem k tomu, že hodnota todos je pole objektů, jak je deklarováno v state, prošli jsme toto pole a vypsali každou z položek todos, tj title.

V React používáme k provedení této iterace metodu map(), která je funkcí vyššího řádu.

Nezapomeňte, že můžete použít platný JavaScript výraz uvnitř JSX pomocí složených závorek, {}.

Pokud zkontrolujeme konzolu svých DevTools, uvidíme varování Reactu, které odstraníme následně.

Zjistíme, že za zpracování TodosList tj. seznamu úkolů, je zodpovědná jiná volaná komponenta. Zde použijeme props.

To, co chceme udělat, je předat data state z dolní komponenty TodoContainer do podřízené komponenty TodosList. Připomeňte si, že můžete předávat data do stromu jako props. a ta může být jako atribut HTML.

Pojďte to použít.

Nejprve přejděte do souboru TodosList.js a vytvořte komponentu s názvem TodosList. V tomto okamžiku můžete vykreslit cokoli. Poté otevřete soubor TodoContainer.js a upravte metodu render() tak, aby vypadala následně:

render() {
  return (
    <div>
      <TodosList todos={this.state.todos} />
    </div>
  );
}

Jelikož používáme instanci komponenty, < todoslist / > v jiném souboru musíme komponentu importovat. Přidejte tedy import do horní části souboru TodoContainer.js.

import TodosList from "./TodosList";

V tomto okamžiku nyní máme data state ve vlastnostech todos. Díky tomuto řádku:

<TodosList todos={this.state.todos} />

Nyní můžeme přistupovat k těmto datům pomocí props v komponentě TodosList. Aktualizujte tedy soubor TodosList.js, aby vypadal takto:

import React from "react"

class TodosList extends React.Component {
  render() {
    return (
      <ul>
        {this.props.todos.map(todo => (
          <li>{todo.title}</li>
        ))}
      </ul>
    )
  }
}

export default TodosList

Uložte soubor. Titulek todos bychom měli mít na obrazovce vykreslený stejně jako dříve. Všimněte si, jak jsme přistupovali k datům stavu z podřízené komponentě TodosList pomocí this.props.todos.

Vždy si pamatujte, že s vlastnostmi můžete přistupovat k údajům o stavu na různých úrovních hierarchie komponent. Tomu se říká prop drilling. A to má co do činění s manuálním získáváním dat z komponenty A do komponenty B prostřednictvím vlastností. Kde složka A je mateřskou složkou B.

Shrnutí

Data todos, která pocházejí ze stavu komponenty TodoContainer, se předávají jako vlastnosti pomocí todos={this.state.todos}. Poté jsme k němu přistupovali this.props.todos zevnitř komponenty TodosList.

Opravme varování konzoly.

Kdykoli něco mapujeme, vytvoří se seznam. React tak vyžaduje aby každý potomek v seznamu měl jedinečnou klíčovou hodnotu. To pomáhá Reactu identifikovat, které položky se změnily, přidaly nebo odstranily.

Chcete-li přidat tuto jedinečnou klíčovou podporu, využijeme výhod, které jsme poskytli id ve stavu TodoContainer. Můžeme k nim přistupovat stejným způsobem, jakým jsme přistupovali k title.

Takže pokračujme a aktualizujme prvek < li > v komponentě TodosList, abychom měli:

<li key={todo.id}>{todo.title}</li>

Uložte soubor a chyba zmizí.

Opět platí, že pokud se vrátíme zpět k diagramu aplikace, uvědomíte si, že za zpracování má zodpovědnost jiná volaná komponenta TodoItem z položek úkolů.

Udělali jsme něco takového dříve. Otevřeme soubor TodoItem.js a vytvořme komponentu s názvem TodoItem. Mezitím můžeme vykreslit cokoli.

Dále importujme komponentu do souboru TodosList.js pomocí tohoto řádku:

import TodoItem from "./TodoItem";

Poté nahraďte prvek < li > v metodě map() tímto řádkem:

<TodoItem key={todo.id} todo={todo} />

V tomto okamžiku jsou ve vlastnosti todo přítomna všechna stavová data. K těmto datům nyní můžeme přistupovat pomocí vlastností v komponentě TodoItem. Aktualizujte tedy soubor TodoItem.js, aby vypadal takto:

import React from "react"

class TodoItem extends React.Component {
  render() {
    return <li>{this.props.todo.title}</li>
  }
}

export default TodoItem

Uložte všechny soubory.

V komponentě TodoItem si všimněte, jak jste přistupovali k použití title pomocí this.props.todo.title.

Než budeme pokračovat, pojďte si krátce promluvit o React Developer Tools.

React Developer Tools

Pokud chcete zkontrolovat a odladit aplikaci, zkontrolovat strom svých komponent nebo zjistit, jak React funguje v reálném čase, budete tento nástroj potřebovat. Je k dispozici jako rozšíření prohlížeče pro Chrome a Firefox.

Pojďte si tento nástroj nainstalovat.

Přejděte na stránku rozšíření pro váš vybraný prohlížeč ( Chrome zde a Firefox zde ) a nainstalujte jej.

Chcete-li jej zobrazit, otevřete devtools prohlížeče kliknutím pravým tlačítkem kdekoli ve výřezu webové stránky a vyberte Prozkoumat nebo Prozkoumat prvek v závislosti na vašem prohlížeči. Poté v inspekčním okně prohlížeče vyberte kartu Komponenty a zobrazte zobrazení hierarchie vaší aplikace.

Reagujte na devtools

Pokud vaše webová stránka v tuto chvíli nepoužívá React, kartu Komponenty neuvidíte .

Ve stromu můžete procházet různými komponentami a prohlížet stav a data vlastností. Prostě si s tím zatím pohrajte.

Vytvoření komponenty funkce

Do tohoto okamžiku jsme k popisu uživatelského rozhraní používali komponentu založenou na třídě.

Později v naší aplikaci použijeme funkční komponentu ke správě funkcí aplikace (tj. Stavovou logiku) pomocí React Hooks.

Nyní si rychle ukážeme, jak snadno integrovat tento typ komponenty do naší aplikace. Prozatím komponenta nebude spravovat žádnou logiku.

Pokud se podíváme na komponenty, které jsme vytvořili, pouze jedna z nich obsahuje údaje o stavu. To je mateřská složka TodoContainer. To znamená, že si tuto komponentu ponecháme jako třídu (alespoň prozatím).

Ostatní komponenty, které jsou v současné době komponenty třídy, mohou být také funkčními komponenty. Je to proto, že nedrží stavová data. To je norma před React Hooks.

Pojďte tedy převést jednu z komponent třídy na komponentu funkce TodoItem.

Převod komponenty založené na třídě na komponentu funkce

V souboru TodoItem.js nahraďte kód následujícím:

import React from "react"

function TodoItem(props) {
  return <li>{props.todo.title}</li>
}

export default TodoItem

Pokud soubor uložíme a zkontrolujeme svou aplikaci, budeme mít stále zobrazeny položky úkolů.

Co se tedy mění?

Zde jsme místo rozšíření třídy React.Component vytvořili funkci se stejným názvem komponenty. Tato funkční součást nevyžaduje metodu render().

Všimněme si také, že this.props ve třídě byla komponenta nahrazena props. A abychom mohli použít props, zahrnuli jsme to jako argument funkce.

Dokud se nenaučíme React Hooks, možná nebudeme vždy vědět, zda použít komponentu funkce nebo třídy. Mnohokrát si po chvíli uvědomíme, že jsme zvolili špatný typ. Ale jak vytvoříme více komponent, bude tato volba snazší.

Jedním z užitečných tipů je, že komponentu třídy, která má v metodě render() pouze označení, lze bezpečně převést na komponentu funkce.

V této části použijeme funkční komponentu jednoduše pro prezentaci, jako v případě komponenty Header. Zde vykreslujeme jednoduchý text nadpisu. Vraťme tedy omponentu TodoItem ke komponentě třídy.

Nyní vytvořme komponentu Header. Přidejte tedy do souboru Header.js následující kód:

import React from "react"

const Header = () => {
  return (
    <header>
      <h1>todos</h1>
    </header>
  )
}

export default Header

Uložte soubor. Dále přejděte do komponenty TodoContainer a importujte soubor v horní části takto:

import Header from "./Header"

Pak zavolejte jeho instanci < header / >

v rámci metody render(), takže máme:

render() {
  return (
    <div>
      <Header />
      <TodosList todos={this.state.todos} />
    </div>
  );
}

Uložte soubor.

Měli bychom mít text záhlaví zobrazený v rozhraní. Všimněte si, jak používáme funkci šipky ES6:

const Header = () => {

Řádek výše je stejný jako tento:

function Header() {

Takže používejte to, co vám nejvíce vyhovuje.

Zatím jsme se dotkli některých zásad Reactu a začali psát naši jednoduchou aplikaci todos. V další části půjdeme hlouběji a vysvětlíme, jak můžete zpracovávat formuláře v Reactu, vyvolávání a zpracování událostí a mnoho dalších.

Rozdíl mezi stavem a vlastnostmi

Vlastnosti Stát
1. Vlastnosti jsou jen pro čtení. Změny stavu mohou být asynchronní.
2. Vlastnosti jsou neměnné. Stav je proměnlivý.
3. Vlastnosti umožňují předávat data z jedné komponenty do jiné jako argument. Stát obsahuje informace o součástech.
4. Podpory jsou přístupné z podřízené komponenty. K podřízeným komponentám nelze získat přístup.
5. Vlastnosti se používají ke komunikaci mezi komponenty. Stavy lze použít k vykreslení dynamických změn s komponentou.
6. Bezstavová součást může mít Vlastnosti. Bezstavové komponenty nemohou mít stav.
7. Díky vlastnostem lze komponenty znovu použít. Stát nemůže zajistit opětovné použití komponent.
8. Vlastnosti jsou externí a jsou řízeny tím, co komponentu vykresluje. Stát je interní a je řízen samotnou složkou React.

Stav Vlastnosti Stav
1. Může získat počáteční hodnotu z nadřazené komponenty? Ano Ano
2. Může být změněn nadřazenou komponentou? Ano Ne
3. Lze nastavit výchozí hodnoty uvnitř komponenty? Ano Ano
4. Může se změnit uvnitř komponenty? Ne Ano
5. Lze nastavit počáteční hodnotu pro podřízené komponenty? Ano Ano
6. Může se změnit v podřízených komponentech? Ano Ne