Režimy práce prostredníctvom stavov podradených komponentov v Reacte
Nech náš pole s produktmi teraz vyzerá nasledovne:
const initProds = [
{id: id(), name: 'prod1', cost: 'cost1', catg: 'catg1'},
{id: id(), name: 'prod2', cost: 'cost2', catg: 'catg2'},
{id: id(), name: 'prod3', cost: 'cost3', catg: 'catg3'},
];
Vypíšme tieto produkty vo forme HTML
tabuľky. Zároveň spravme to, aby po kliknutí
na ľubovoľnú bunku tabuľky sa v tejto bunke objavilo
vstupné pole pre editáciu. Na vyriešenie úlohy
urobme 3 komponenty.
Komponent Products bude uchovávať stav
s produktmi a používať komponenty Product
pre výpis produktov. Komponent Product
naopak bude tiež používať komponenty
ProductField pre výpis konkrétneho
pola produktu (názvu, ceny, kategórie).
Komponent ProductField bude buď
zobrazovať text poľa, alebo vstupné pole pre jeho
editáciu. Pritom režim editácie
alebo zobrazenia nech je regulovaný stavom
daného komponentu.
To znamená, že režim nebudeme ukladať do nadradeného stavu. Tam by to bolo veľmi nepohodlné, pretože by sme museli uvádzať režim pre každé pole produktu, čo by premenilo náš stav na niečo podobné:
const initProds = [
[
{field: 'name', value: 'prod1', isEdit: false},
{field: 'cost', value: 'cost1', isEdit: false},
{field: 'catg', value: 'catg1', isEdit: false},
],
[
{field: 'name', value: 'prod2', isEdit: false},
{field: 'cost', value: 'cost2', isEdit: false},
{field: 'catg', value: 'catg2', isEdit: false},
],
[
{field: 'name', value: 'prod3', isEdit: false},
{field: 'cost', value: 'cost3', isEdit: false},
{field: 'catg', value: 'catg3', isEdit: false},
],
]
My však neurobíme takýto stav,
ale ponecháme ten, ktorý bol. Jednoducho každá
inštancia komponentu ProductField
pomocou svojho stavu bude regulovať
režim: buď editáciu, alebo zobrazenie.
Takto sa stane, že nadradený komponent bude uchovávať stav s údajmi, a náš vnorený komponent bude tieto údaje prijímať cez props a zároveň bude mať vlastný stav pre zmenu svojho režimu.
Takže, realizujme popísané.
Komponent Products
function Products() {
const [prods, setProds] = useState(initProds);
function changeField(id, field, event) {
setProds(prods.map(prod => {
if (prod.id === id) {
prod[field] = event.target.value;
}
return prod;
}));
}
const rows = prods.map(prod => {
return <Product
key ={prod.id}
id ={prod.id}
name={prod.name}
cost={prod.cost}
catg={prod.catg}
changeField={changeField}
/>;
});
return <div>
<table>
<tbody>
{rows}
</tbody>
</table>
</div>;
}
Komponent Product
function Product({ id, name, cost, catg, changeField }) {
return <tr>
<ProductField id={id} text={name} type="name" changeField={changeField} />
<ProductField id={id} text={cost} type="cost" changeField={changeField} />
<ProductField id={id} text={catg} type="catg" changeField={changeField} />
</tr>;
}
Komponent ProductField
function ProductField({ id, text, type, changeField }) {
const [isEdit, setIsEdit] = useState(false);
return <td>
{
isEdit
? <input
value={text}
onChange={event => changeField(id, type, event)}
onBlur={() => setIsEdit(false)}
/>
: <span onClick={() => setIsEdit(true)}>{text}</span>
}
</td>;
}
Praktické úlohy
Vykonajte podobné operácie s komponentmi
Users a User, ktoré ste vytvorili
v predchádzajúcich lekciách.