Tilstandsdrevne tilstande i underkomponenter i React
Lad vores array med produkter nu se ud som følger:
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'},
];
Lad os vise disse produkter som en HTML
tabel. Lad os også gøre det sådan, at når der klikkes
på en hvilken som helst celle i tabellen, vises
et inputfelt til redigering i denne celle. For at løse opgaven
laver vi 3 komponenter.
Komponenten Products vil gemme tilstanden
med produkter og bruge komponenter Product
til at vise produkter. Komponenten Product
vil til gengæld også bruge komponenter
ProductField til at vise et bestemt
produktfelt (navn, pris, kategori).
Komponenten ProductField vil enten
vise feltets tekst eller et inputfelt til dens
redigering. Lad redigerings- eller visningstilstand
reguleres af denne komponents tilstand.
Det vil sige, at vi ikke vil gemme tilstanden i den overordnede tilstand. Det ville være meget ubelejligt der, da vi ville være nødt til at angive tilstanden for hvert produktfelt, hvilket ville gøre vores tilstand til noget lignende:
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},
],
]
Vi vil dog ikke lave en sådan tilstand,
men beholde den, som var der. Blot hver
instans af komponenten ProductField
ved hjælp af sin egen tilstand vil regulere
tilstanden: enten redigering eller visning.
På denne måde vil det ske, at den overordnede komponent vil gemme tilstanden med data, og vores barnekomponent vil modtage disse data via props og samtidig have sin egen tilstand til at ændre sin tilstand.
Så lad os implementere det beskrevne.
Komponenten 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>;
}
Komponenten 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>;
}
Komponenten 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>;
}
Praktiske opgaver
Udfør lignende operationer med komponenterne
Users og User, som du har oprettet
i tidligere lektioner.