Chế độ làm việc thông qua state của các component con trong React
Giả sử mảng sản phẩm của chúng ta bây giờ trông như sau:
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'},
];
Hãy hiển thị các sản phẩm này dưới dạng bảng HTML.
Đồng thời, hãy làm sao để khi nhấp vào bất kỳ ô nào
trong bảng, một ô nhập liệu (input) sẽ xuất hiện
trong ô đó để chỉnh sửa. Để giải quyết nhiệm vụ,
chúng ta sẽ tạo 3 component.
Component Products sẽ lưu trữ state
chứa các sản phẩm và sử dụng các component Product
để hiển thị sản phẩm. Component Product
lần lượt cũng sẽ sử dụng các component
ProductField để hiển thị một trường
cụ thể của sản phẩm (tên, giá, danh mục).
Component ProductField sẽ hoặc là
hiển thị văn bản của trường, hoặc là ô nhập liệu để
chỉnh sửa nó. Và chế độ chỉnh sửa
hoặc hiển thị hãy để được điều chỉnh bởi state
của component này.
Tức là chúng ta sẽ không lưu trữ chế độ trong state của component cha. Ở đó sẽ rất bất tiện, bởi vì chúng ta sẽ phải chỉ định chế độ cho mỗi trường sản phẩm, điều này sẽ biến state của chúng ta thành một thứ tương tự như sau:
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},
],
]
Tuy nhiên, chúng ta sẽ không tạo state như vậy,
mà sẽ giữ nguyên cái đã có. Chỉ cần mỗi
thể hiện của component ProductField
thông qua state của chính nó sẽ điều chỉnh
chế độ: hoặc chỉnh sửa, hoặc hiển thị.
Như vậy, sẽ thành ra là component cha sẽ lưu trữ state chứa dữ liệu, còn component cháu của chúng ta sẽ nhận những dữ liệu này thông qua props và đồng thời sẽ có state riêng để thay đổi chế độ của nó.
Vậy, hãy cùng thực hiện những điều đã mô tả.
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>;
}
Bài tập thực hành
Hãy thực hiện các thao tác tương tự với các component
Users và User do bạn tạo
trong các bài học trước.