Пусть наш массив с продуктами теперь выглядит следующим образом:
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
таблицы. При этом сделаем так, чтобы по нажатию
на любую ячейку таблицы в этой ячейке появлялся
инпут для редактирования. Для решения задачи
сделаем 3
компонента.
Компонент Products
будет хранить стейт
с продуктами и использовать компоненты Product
для вывода продуктов. Компонент Product
в свою очередь также будет использовать компоненты
ProductField
для вывода определенного
поля продукта (названия, цены, категории).
Компонент ProductField
будет либо
показывать текст поля, либо инпут для его
редактирования. При этом режим редактирования
или показа пусть регулируется стейтом
данного компонента.
То есть мы не будем хранить режим в родительском стейте. Там это было бы очень неудобно, так как нам пришлось бы указывать режим для каждого поля продукта, что превратило бы наш стейт в нечто подобное:
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},
],
]
Мы, однако, не будем делать такой стейт,
а оставим тот, который был. Просто каждый
экземпляр компонента ProductField
с помощью своего стейта будет регулировать
режим: либо редактирование, либо показ.
Таким образом получится, что родительский компонент будет хранить стейт с данными, а наш внучатый компонент будет получать эти данные через пропсы и при этом будет иметь свой стейт для изменения своего режима.
Итак, давайте реализуем описанное.
Компонент 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>;
}
Компонент 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>;
}
Компонент 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>;
}
Практические задачи
Проделайте аналогичные операции с компонентами
Users
и User
, созданными вами
в предыдущих уроках.