Chỉnh sửa state của component cha trong component con trong React
Bây giờ hãy chỉnh sửa sản phẩm của chúng ta bằng các ô nhập liệu. Để làm điều này, trong component con chúng ta sẽ tạo một nút.
Khi nhấp lần đầu vào nút này, thay vì tên và giá của sản phẩm, hãy hiển thị các ô nhập liệu để chỉnh sửa chúng, và khi nhấp lần thứ hai thay vì các ô nhập liệu, lại hiển thị văn bản.
Chúng ta sẽ thay đổi mảng sản phẩm, thêm vào
thuộc tính isEdit (và để đơn giản, chúng ta sẽ bỏ phần làm việc với giỏ hàng):
const initProds = [
{id: id(), name: 'product1', cost: 100, isEdit: false},
{id: id(), name: 'product2', cost: 200, isEdit: false},
{id: id(), name: 'product3', cost: 300, isEdit: false},
];
Component Product
Hãy tạo một nút để chỉnh sửa trong sản phẩm:
function Product({ id, name, cost, isEdit }) {
return <div>
name: <span>{name}</span>
cost: <span>{cost}</span>
<button>edit</button>
</div>;
}
Hãy làm sao cho khi nhấp vào nút này
một hàm nào đó toggleMode sẽ được gọi,
hàm này được truyền từ component cha:
function Product({ id, name, cost, isEdit, toggleMode }) {
return <div>
name: <span>{name}</span>
cost: <span>{cost}</span>
<button onClick={() => toggleMode(id)}>
edit
</button>
</div>;
}
Hiện tại chúng ta chưa có triển khai toggleMode,
nhưng chúng ta biết rằng nó sẽ nằm
trong component cha, nhận tham số là
id của sản phẩm và thay đổi thuộc tính isEdit
của sản phẩm thành giá trị ngược lại.
Chúng ta cũng sẽ làm sao cho văn bản của nút thay đổi sau mỗi lần nhấp:
function Product({ id, name, cost, isEdit, toggleMode }) {
return <div>
name: <span>{name}</span>
cost: <span>{cost}</span>
<button onClick={() => toggleMode(id)}>
{isEdit ? 'save': 'edit'}
</button>
</div>;
}
Bây giờ hãy làm sao cho trong chế độ chỉnh sửa, chúng ta có các ô nhập liệu với dữ liệu, còn trong chế độ thông thường - các thẻ span:
function Product({ id, name, cost, isEdit, toggleMode }) {
return <div>
name: {isEdit ? <input value={name} /> : <span>{name}</span>}
cost: {isEdit ? <input value={cost} /> : <span>{cost}</span>}
<button onClick={() => toggleMode(id)}>
{isEdit ? 'save': 'edit'}
</button>
</div>;
}
Hãy liên kết sự kiện onChange với các ô nhập liệu của chúng ta,
trong đó chúng ta sẽ gọi một hàm nào đó của component cha
là editProd:
function Product({ id, name, cost, isEdit, toggleMode, editProd }) {
return <div>
name: {
isEdit
? <input value={name} onChange={event => editProd(id, 'name', event)} />
: <span>{ name }</span>
}
cost: {
isEdit
? <input value={cost} onChange={event => editProd(id, 'cost', event)} />
: <span>{ cost }</span>
}
<button onClick={() => toggleMode(id)}>
{isEdit ? 'save': 'edit'}
</button>
</div>;
}
Component Products
Bây giờ hãy chuyển sang component Products.
Chúng ta sẽ triển khai hàm toggleMode trong đó:
function toggleMode(id) {
setProds(prods.map(prod => {
if (prod.id === id) {
prod.isEdit = !prod.isEdit;
}
return prod;
}));
}
Chúng ta cũng sẽ triển khai hàm editProd trong đó:
function editProd(id, field, event) {
setProds(prods.map(prod => {
if (prod.id === id) {
prod[field] = event.target.value;
}
return prod;
}));
}
Chúng ta sẽ truyền các hàm toggleMode và editProd của chúng ta
dưới dạng thuộc tính vào thẻ sản phẩm:
const items = prods.map(prod => {
return <Product
key ={prod.id}
id ={prod.id}
name={prod.name}
cost={prod.cost}
isEdit={prod.isEdit}
toggleMode={toggleMode}
editProd={editProd}
/>;
});
Mã cuối cùng của component Products
sẽ như sau:
function Products() {
const [prods, setProds] = useState(initProds);
function toggleMode(id) {
setProds(prods.map(prod => {
if (prod.id === id) {
prod.isEdit = !prod.isEdit;
}
return prod;
}));
}
function editProd(id, field, event) {
setProds(prods.map(prod => {
if (prod.id === id) {
prod[field] = event.target.value;
}
return prod;
}));
}
const result = prods.map(prod => {
return <Product
key ={prod.id}
id ={prod.id}
name={prod.name}
cost={prod.cost}
isEdit={prod.isEdit}
toggleMode={toggleMode}
editProd={editProd}
/>;
});
return <div>
{result}
</div>;
}
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 mà bạn đã tạo
trong các bài học trước.