#reactjs
#reactjs
Вопрос:
Имея следующий код, я надеюсь, что при изменении значения цены и количества статус продуктов изменяется в родительском компоненте, это работает частично, потому что есть задержка в обновлении информации, я должен записать дважды значение цены и количества, чтобы увидеть какой-то результат. В чем причина этой задержки при изменении значения переменных состояния?
import React, { useState } from "react";
const initialState = [
{
id: 1,
name: "Nintendo switch",
price: 250,
quantity: 0,
subTotal: 0
},
{
id: 2,
name: "Nintendo 3DS",
price: 199,
quantity: 0,
subTotal: 0
},
{
id: 3,
name: "playstation 4",
price: 300,
quantity: 0,
subTotal: 0
}
];
function Totals({ products }) {
function getTotal(key) {
return products.reduce((previousValue, currentValue) => {
return (previousValue = currentValue[key]);
}, 0);
}
return (
<tr>
<td />
<td>{getTotal("price")}</td>
<td>{getTotal("quantity")}</td>
<td>{getTotal("subTotal")}</td>
</tr>
);
}
function Product({ product, onChange }) {
const [price, setPrice] = useState(product.price);
const [quantity, setQuantity] = useState(product.quantity);
function onChangePrice(event) {
setPrice(event.target.value);
onChange({ id: product.id, price, quantity });
}
function onChangeQuantity(event) {
setQuantity(event.target.value);
onChange({ id: product.id, price, quantity });
}
return (
<tr>
<td>{product.name}</td>
<td>
<input onChange={onChangePrice} value={price} />
</td>
<td>
<input onChange={onChangeQuantity} value={quantity} />
</td>
<td>{product.subTotal}</td>
</tr>
);
}
function App() {
const [products, setProducts] = useState(initialState);
function onChangeHandler(entry) {
const output = products.map(product =>
product.id === entry.id
? {
...product,
price: entry.price,
quantity: entry.quantity,
subTotal: entry.price * entry.quantity
}
: product
);
setProducts(output);
}
return (
<table>
<thead>
<tr>
<th>Name</th>
<th>Price</th>
<th>Quantity</th>
<th>Sub total</th>
</tr>
</thead>
<tbody>
{products.map(product => (
<Product
key={product.id}
product={product}
onChange={onChangeHandler}
/>
))}
<Totals products={products} />
</tbody>
</table>
);
}
export default App;
Пожалуйста, взгляните на этот пример
Ответ №1:
Проблема в том, что вы по существу сохраняете состояние в 2 местах, и они не всегда согласуются. Product
Компонент должен быть без состояния, поскольку вы поддерживаете состояние в своем списке продуктов.
function Product({ product, onChange }) {
function onChangePrice(e) {
onChange({ id: product.id, price: e.target.value, quantity: product.quantity });
}
function onChangeQuantity(e) {
onChange({ id: product.id, quantity: e.target.value, price: product.price });
}
return (
<tr>
<td>{product.name}</td>
<td>
<input onChange={onChangePrice} value={product.price} />
</td>
<td>
<input onChange={onChangeQuantity} value={product.quantity} />
</td>
<td>{product.subTotal}</td>
</tr>
);
}
Ответ №2:
Хотя Product
локальные price
и quantity
установлены правильно, вы вызываете onChange
, который является реквизитом, переданным родительским компонентом, со старыми значениями:
function onChangePrice(event) {
setPrice(event.target.value);
onChange({ id: product.id, price, quantity });
}
function onChangeQuantity(event) {
setQuantity(event.target.value);
onChange({ id: product.id, price, quantity });
}
Если вам действительно нужно по какой-либо причине сохранить цену и количество в дочернем компоненте, а также в родительском компоненте, обязательно вызывайте onChange
с event.target.value
вместо старых значений в price
и quantity
:
function onChangePrice(event) {
setPrice(event.target.value);
onChange({ id: product.id, price: event.target.value, quantity });
}
function onChangeQuantity(event) {
setQuantity(event.target.value);
onChange({ id: product.id, price, quantity: event.target.value });
}