更改数组中的对象不会触发 html React 中的更改
Changing object in an array does not trigger change in html React
我要编辑的对象以 JSON 格式编辑,但只有以前的数据显示在浏览器中。我使用这些挂钩从本地存储中获取产品列表
const Cart = () => {
const [products, setProducts] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(()=>{
setProducts(loadCart());
setLoading(false)
},[])
然后我映射所有对象
const mapProducts = (products) => {
return (
<>
{products.map((product) => {
return (
<>
<div className="cart-detail">
<h4>{product.name} - {product.price}$
/ total: {product.price * product.amount}$</h4>
<h4>{product.amount}</h4>
<button onClick={() => incrementAmount(product)}>+</button>
</div>
</>
)
})}
</>
)
}
return (
<Base title="Cart">
{loading && <h1>Loading...</h1>}
{!loading && mapProducts(products)}
</Base>
)
incrementAmount()
函数看起来像这样:
const incrementAmount = (product) => {
let tempList = products
for (let i = 0; i < tempList.length; i++) {
if (tempList[i].id === product.id) {
tempList[i].amount++;
}
}
setProducts(tempList)
}
从我在控制台中看到的情况来看,数组看起来很好,我想要编辑的对象已被编辑。 FE:我有一个对象 {name:"hoodie", amount:3} 在点击 "+" 按钮后它正确地更改为 {name:"hoodie", amount:4}(在两个 products
和 tempList
) 但仅在控制台中,在文档中它仍然显示 product.amount
为 3 我不知道为什么
您可以传递一个函数,而不是将对象传递给 setState
,当您有一个对象进入您想要保留旧值的状态时,您必须使用一个函数。
因为state
可能会异步更新,所以你不应该依赖它们的值来计算下一个状态。
您必须像这样更改 incrementAmount()
函数:
const incrementAmount = (product) => {
setProducts(prevState => {
const newState = [...prevState];
for (let i = 0; i < newState.length; i++) {
if (newState[i].id === product.id) {
newState[i].amount++;
}
}
return newState;
});
}
这是因为只有当状态发生变化时,react 才会触发重新渲染。当您在 incrementAmount
中调用 setProducts
时,您实际上是在传递相同的对象(更新了一个嵌套的 属性)。所以 React 不会将此注册为状态更改。这是由于对象和数组在 Javascript 中的工作方式。
为了让您的代码正常工作,请将 let tempList = products
更改为 let tempList = [...products]
。这将在内存中创建一个新对象并从 products
复制值。最后,当您将其传递给 setProducts
时,将触发重新渲染以更新您的 HTML.
我要编辑的对象以 JSON 格式编辑,但只有以前的数据显示在浏览器中。我使用这些挂钩从本地存储中获取产品列表
const Cart = () => {
const [products, setProducts] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(()=>{
setProducts(loadCart());
setLoading(false)
},[])
然后我映射所有对象
const mapProducts = (products) => {
return (
<>
{products.map((product) => {
return (
<>
<div className="cart-detail">
<h4>{product.name} - {product.price}$
/ total: {product.price * product.amount}$</h4>
<h4>{product.amount}</h4>
<button onClick={() => incrementAmount(product)}>+</button>
</div>
</>
)
})}
</>
)
}
return (
<Base title="Cart">
{loading && <h1>Loading...</h1>}
{!loading && mapProducts(products)}
</Base>
)
incrementAmount()
函数看起来像这样:
const incrementAmount = (product) => {
let tempList = products
for (let i = 0; i < tempList.length; i++) {
if (tempList[i].id === product.id) {
tempList[i].amount++;
}
}
setProducts(tempList)
}
从我在控制台中看到的情况来看,数组看起来很好,我想要编辑的对象已被编辑。 FE:我有一个对象 {name:"hoodie", amount:3} 在点击 "+" 按钮后它正确地更改为 {name:"hoodie", amount:4}(在两个 products
和 tempList
) 但仅在控制台中,在文档中它仍然显示 product.amount
为 3 我不知道为什么
您可以传递一个函数,而不是将对象传递给 setState
,当您有一个对象进入您想要保留旧值的状态时,您必须使用一个函数。
因为state
可能会异步更新,所以你不应该依赖它们的值来计算下一个状态。
您必须像这样更改 incrementAmount()
函数:
const incrementAmount = (product) => {
setProducts(prevState => {
const newState = [...prevState];
for (let i = 0; i < newState.length; i++) {
if (newState[i].id === product.id) {
newState[i].amount++;
}
}
return newState;
});
}
这是因为只有当状态发生变化时,react 才会触发重新渲染。当您在 incrementAmount
中调用 setProducts
时,您实际上是在传递相同的对象(更新了一个嵌套的 属性)。所以 React 不会将此注册为状态更改。这是由于对象和数组在 Javascript 中的工作方式。
为了让您的代码正常工作,请将 let tempList = products
更改为 let tempList = [...products]
。这将在内存中创建一个新对象并从 products
复制值。最后,当您将其传递给 setProducts
时,将触发重新渲染以更新您的 HTML.