Λειτουργίες μέσω των state των θυγατρικών components στο React
Ας υποθέσουμε ότι ο πίνακας μας με τα προϊόντα τώρα μοιάζει ως εξής:
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'},
];
Ας εμφανίσουμε αυτά τα προϊόντα σε μορφή πίνακα HTML.
Ταυτόχρονα, ας κάνουμε έτσι ώστε με το πάτημα
σε οποιοδήποτε κελί του πίνακα σε αυτό το κελί να εμφανίζεται
ένα input για επεξεργασία. Για την επίλυση του προβλήματος
θα φτιάξουμε 3 components.
Το component Products θα αποθηκεύει το state
με τα προϊόντα και θα χρησιμοποιεί τα components Product
για την εμφάνιση των προϊόντων. Το component Product
με τη σειρά του θα χρησιμοποιεί επίσης components
ProductField για την εμφάνιση ενός συγκεκριμένου
πεδίου του προϊόντος (όνομα, τιμή, κατηγορία).
Το component ProductField θα εμφανίζει είτε
το κείμενο του πεδίου, είτε ένα input για την
επεξεργασία του. Σε αυτήν την περίπτωση, η λειτουργία επεξεργασίας
ή εμφάνισης ας ρυθμίζεται από το state
αυτού του component.
Δηλαδή δεν θα αποθηκεύουμε τη λειτουργία στο γονικό state. Εκεί θα ήταν πολύ άβολο, αφού θα έπρεπε να καθορίσουμε τη λειτουργία για κάθε πεδίο του προϊόντος, κάτι που θα μετατρέψει το state μας σε κάτι παρόμοιο με αυτό:
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},
],
]
Εμείς, ωστόσο, δεν θα φτιάξουμε ένα τέτοιο state,
αλλά θα κρατήσουμε αυτό που ήταν. Απλά κάθε
αντικείμενο του component ProductField
με τη βοήθεια του δικού του state θα ρυθμίζει
τη λειτουργία: είτε επεξεργασία, είτε εμφάνιση.
Έτσι θα προκύψει ότι το γονικό component θα αποθηκεύει το state με τα δεδομένα, και το εγγόνι component θα λαμβάνει αυτά τα δεδομένα μέσω props και ταυτόχρονα θα έχει το δικό του state για αλλαγή της λειτουργίας του.
Λοιπόν, ας υλοποιήσουμε όσα περιγράψαμε.
Component 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>;
}
Component 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>;
}
Component 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>;
}
Πρακτικές Ασκήσεις
Εκτελέστε παρόμοιες λειτουργίες με τα components
Users και User, που δημιουργήσατε
σε προηγούμενα μαθήματα.