Thay đổi state của component cha trong component con trong React
Trong bài học trước, state chứa dữ liệu được lưu trữ trong component cha, còn các component con nhận dữ liệu đó dưới dạng props.
Bây giờ giả sử chúng ta muốn thay đổi sản phẩm của mình.
Chúng ta hãy tạo, ví dụ, một nút bấm sẽ
thêm sản phẩm của chúng ta vào giỏ hàng. Đầu tiên
hãy thêm vào mảng sản phẩm của chúng ta
trường inCart, cho biết sản phẩm
có trong giỏ hàng hay không:
const initProds = [
{id: id(), name: 'product1', cost: 100, inCart: false},
{id: id(), name: 'product2', cost: 200, inCart: false},
{id: id(), name: 'product3', cost: 300, inCart: false},
];
Trong component Products, vào thẻ chứa sản phẩm
chúng ta thêm một thuộc tính nữa là inCart:
function Products() {
const [prods, setProds] = useState(initProds);
const items = prods.map(prod => {
return <Product
key ={prod.id}
name ={prod.name}
cost ={prod.cost}
inCart={prod.inCart}
/>;
});
return <div>
{items}
</div>;
}
Hãy trong component con Product
tạo phần hiển thị thông tin về giỏ hàng và nút
để thêm vào giỏ hàng:
function Product({ id, name, cost, inCart }) {
return <div>
name: <span>{name}</span>,
cost: <span>{cost}</span>,
<span>{inCart ? 'in cart' : 'not in cart'}</span>
<button>to cart</button>
</div>;
}
Triển khai chức năng thêm
Theo quy tắc của React, một component không được
thay đổi props của chính nó. Điều này có nghĩa là
component con không thể tự mình
thêm vào giỏ hàng bằng cách thay đổi prop inCart.
Điều đó không đúng.
Cách đúng sẽ là yêu cầu component cha
thay đổi state prods của nó, đặt
một sản phẩm cụ thể vào giỏ hàng.
Hãy xem cách thực hiện điều này.
Trong component cha, chúng ta tạo hàm addToCart,
hàm này nhận tham số id của sản phẩm
và đối với sản phẩm đó, thay đổi thuộc tính inCart
thành true:
function addToCart(id) {
setProds(prods.map(prod => {
if (prod.id === id) {
prod.inCart = true;
}
return prod;
}));
}
Vào thẻ chứa sản phẩm, chúng ta thêm một thuộc tính, trong đó
chúng ta truyền hàm mà chúng ta đã tạo, cũng như
một thuộc tính, trong đó chúng ta truyền id của sản phẩm:
const items = prods.map(prod => {
return <Product
key ={prod.id}
id ={prod.id}
name ={prod.name}
cost ={prod.cost}
inCart ={prod.inCart}
addToCart={addToCart}
/>;
});
Như bạn thấy, vào props của components, bạn có thể truyền không chỉ dữ liệu nào đó, mà cả các hàm nữa.
Code cuối cùng của class Products sẽ
như sau:
function Products() {
const [prods, setProds] = useState(initProds);
function addToCart(id) {
setProds(prods.map(prod => {
if (prod.id === id) {
prod.inCart = true;
}
return prod;
}));
}
const items = prods.map(prod => {
return <Product
key ={prod.id}
id ={prod.id}
name ={prod.name}
cost ={prod.cost}
inCart ={prod.inCart}
addToCart={addToCart}
/>;
});
return <div>
{items}
</div>;
}
Bây giờ trong class con, chúng ta sẽ có quyền truy cập vào
hàm addToCart. Hãy gọi hàm này
khi click vào nút, truyền cho nó tham số
id của sản phẩm:
function Product({ id, name, cost, inCart, addToCart }) {
return <div>
name: <span>{name}</span>,
cost: <span>{cost}</span>,
<span>{inCart ? 'in cart' : 'not in cart'}</span>
<button onClick={() => addToCart(id)}>to cart</button>
</div>;
}
Kết quả là, khi click vào nút trong component con, hàm của component cha sẽ được gọi, hàm này sẽ thay đổi state của component cha. Việc thay đổi state của component cha sẽ kích hoạt re-render và vẽ lại sản phẩm của chúng ta, truyền cho nó prop đã được thay đổi.
Hãy lấy component User từ bài học
trước. Hãy làm sao để trong đó xuất hiện
nút để ban người dùng.