Tryby pracy przez stany komponentów potomnych w React
Załóżmy, że nasza tablica z produktami wygląda teraz następująco:
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'},
];
Wyświetlmy te produkty w postaci tabeli HTML.
Jednocześnie zróbmy tak, aby po kliknięciu
na dowolną komórkę tabeli w tej komórce pojawiło się
pole wprowadzania do edycji. Aby rozwiązać zadanie
stworzymy 3 komponenty.
Komponent Products będzie przechowywać stan
z produktami i używać komponentów Product
do wyświetlania produktów. Komponent Product
z kolei również będzie używać komponentów
ProductField do wyświetlania określonego
pola produktu (nazwy, ceny, kategorii).
Komponent ProductField będzie albo
wyświetlać tekst pola, albo pole wprowadzania do jego
edycji. Przy tym tryb edycji
lub wyświetlania niech reguluje się stanem
tego komponentu.
Czyli nie będziemy przechowywać trybu w stanie rodzica. Byłoby to bardzo niewygodne, ponieważ musielibyśmy określać tryb dla każdego pola produktu, co przekształciłoby nasz stan w coś podobnego do:
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 jednak nie zrobimy takiego stanu,
a pozostawimy ten, który był. Po prostu każda
instancja komponentu ProductField
za pomocą swojego stanu będzie regulować
tryb: albo edycję, albo wyświetlanie.
W ten sposób okaże się, że komponent rodzica będzie przechowywać stan z danymi, a nasz komponent wnuka będzie otrzymywać te dane przez właściwości i przy tym będzie miał swój stan do zmiany swojego trybu.
A więc, zrealizujmy opisane.
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>;
}
Zadania praktyczne
Wykonaj podobne operacje z komponentami
Users i User, stworzonymi przez ciebie
w poprzednich lekcjach.