状态更改时组件不重新渲染
Component not re-rendering when state is changed
我正在尝试在 React 函数组件中使用更新状态,但它不会立即重新渲染。
我的应用程序输入每个产品的 material 成本并计算该产品的总和。我希望在更新输入后重新呈现组件以显示更新后的总数。每次 material 成本更改时,似乎总计已计算并且状态正在更新,但我无法让显示的总计说出新金额。
这是我的应用程序的屏幕截图(为简单起见,删除了 table 中元素的一些代码)
这就是数据的样子。在这个例子中,我保存了数组的第一个元素。
export let data =
{
name: "Name",
description:
"",
products: [
{
id: 1,
name: "Name 1",
material: 1.05,
time: 25,
total: 0,
},
{
id: 2,
name: "Name 2",
material: 3,
time: 252,
total: 0,
},
],
}
这是父组件。它具有主要的渲染功能以及 setTotal 和 setMaterial 功能。通过每个 productData.products 渲染映射,以便子组件可以渲染它们。
setTotal 和 setMaterial 函数几乎相同(我确信有一种方法可以重构它)。这段代码似乎可以很好地更新状态,尽管我确实注意到在这些函数中执行 console.log() 是行不通的。
function CompareCard({ type, labor }) {
const [productData, setProductData] = useState(data);
const setTotal = () => {
function setTotalUpdate(id, total) {
const productPrevious = productData.products.find(function (rec) {
return rec.id === id;
});
const productUpdated = {
...productPrevious,
total: total,
};
const productNew = productData.products.map(function (rec) {
return rec.id === id ? productUpdated : rec;
});
const productFullNew = {
...productData,
products: productNew,
};
setProductData(productFullNew);
}
};
const setMaterial = () => {
function setMaterialUpdate(id, materialCost) {
const productPrevious = productData.products.find(function (rec) {
return rec.id === id;
});
const productUpdated = {
...productPrevious,
material: materialCost,
};
const productNew = productData.products.map(function (rec) {
return rec.id === id ? productUpdated : rec;
});
console.log("productsNew:", productNew);
const productFullNew = {
...productData,
products: productNew,
};
setProductData(productFullNew);
}
};
return (
<div className="Card">
<h3> {productData.name} </h3>
<p>{productData.description}</p>
<table className="table">
<thead>
<tr>
<th scope="col">
<p>
<b> Material </b>
</p>
</th>
<th scope="col">
<p>
<b> Labor </b>
</p>
</th>
<th scope="col">
<p>
<b> Total</b>
</p>
</th>
</tr>
</thead>
<tbody id={`${productData.name}`}>
{productData.products.map((product) => {
return (
<Products
key={product.id}
product={product}
labor={3}
setMaterial={setMaterial}
setTotal={setTotal}
/>
);
})}
</tbody>
</table>
</div>
);
}
export default CompareCard;
这是子元素。它单独处理每个产品。
第一个calcTotal()用于设置原始总数。此调用有效,但当 material 稍后更改时,总计不会继续重新呈现。
import React, { useState, useEffect } from "react";
function Products({ product, labor, setMaterial, setTotal }) {
function setMaterialState(newMaterial) {
product.material = newMaterial;
}
function calcTotal() {
product.total = labor + product.material;
}
if (product.total === 0) {
calcTotal();
}
useEffect(() => {
setTotal(product.id, product.total);
}, [product.total]);
useEffect(() => {
setMaterial(product.id, product.material);
//setTotal(product.id, product.material + labor);
}, [product.material]);
function ProductMaterial() {
const [name, setName] = useState("");
function handleChange(e) {
setName(parseFloat(e.target.value));
setMaterialState(parseFloat(e.target.value));
setMaterial(product.id, product.material);
calcTotal();
setTotal(product.id, product.total);
}
return (
<input
type="number"
name="firstName"
onChange={handleChange}
value={product.material}
/>
);
}
return (
<tr key={product.name}>
<td>
<ProductMaterial product={product} />{" "}
<td id={`total-${product.id}`}>{product.total}</td>
</tr>
);
}
export default Products;
它不起作用,因为 setMaterial 和 setTotal 都有一个内部函数,但内部函数永远不会执行。
您应该删除函数 setTotalUpdate 和 setMaterialUpdate 来解决您的更新问题,如下所示。
function CompareCard({ type, labor }) {
const [productData, setProductData] = useState(data);
const setTotal = (id, total) => {
const productPrevious = productData.products.find(function (rec) {
return rec.id === id;
});
const productUpdated = {
...productPrevious,
total: total,
};
const productNew = productData.products.map(function (rec) {
return rec.id === id ? productUpdated : rec;
});
const productFullNew = {
...productData,
products: productNew,
};
setProductData(productFullNew);
};
const setMaterial = (id, materialCost) => {
const productPrevious = productData.products.find(function (rec) {
return rec.id === id;
});
const productUpdated = {
...productPrevious,
material: materialCost,
};
const productNew = productData.products.map(function (rec) {
return rec.id === id ? productUpdated : rec;
});
console.log("productsNew:", productNew);
const productFullNew = {
...productData,
products: productNew,
};
setProductData(productFullNew);
};
return (
<div className="Card">
<h3> {productData.name} </h3>
<p>{productData.description}</p>
<table className="table">
<thead>
<tr>
<th scope="col">
<p>
<b> Material </b>
</p>
</th>
<th scope="col">
<p>
<b> Labor </b>
</p>
</th>
<th scope="col">
<p>
<b> Total</b>
</p>
</th>
</tr>
</thead>
<tbody id={`${productData.name}`}>
{productData.products.map((product) => {
return (
<Products
key={product.id}
product={product}
labor={3}
setMaterial={setMaterial}
setTotal={setTotal}
/>
);
})}
</tbody>
</table>
</div>
);
}
export default CompareCard;
我正在尝试在 React 函数组件中使用更新状态,但它不会立即重新渲染。
我的应用程序输入每个产品的 material 成本并计算该产品的总和。我希望在更新输入后重新呈现组件以显示更新后的总数。每次 material 成本更改时,似乎总计已计算并且状态正在更新,但我无法让显示的总计说出新金额。
这是我的应用程序的屏幕截图(为简单起见,删除了 table 中元素的一些代码)
export let data =
{
name: "Name",
description:
"",
products: [
{
id: 1,
name: "Name 1",
material: 1.05,
time: 25,
total: 0,
},
{
id: 2,
name: "Name 2",
material: 3,
time: 252,
total: 0,
},
],
}
这是父组件。它具有主要的渲染功能以及 setTotal 和 setMaterial 功能。通过每个 productData.products 渲染映射,以便子组件可以渲染它们。
setTotal 和 setMaterial 函数几乎相同(我确信有一种方法可以重构它)。这段代码似乎可以很好地更新状态,尽管我确实注意到在这些函数中执行 console.log() 是行不通的。
function CompareCard({ type, labor }) {
const [productData, setProductData] = useState(data);
const setTotal = () => {
function setTotalUpdate(id, total) {
const productPrevious = productData.products.find(function (rec) {
return rec.id === id;
});
const productUpdated = {
...productPrevious,
total: total,
};
const productNew = productData.products.map(function (rec) {
return rec.id === id ? productUpdated : rec;
});
const productFullNew = {
...productData,
products: productNew,
};
setProductData(productFullNew);
}
};
const setMaterial = () => {
function setMaterialUpdate(id, materialCost) {
const productPrevious = productData.products.find(function (rec) {
return rec.id === id;
});
const productUpdated = {
...productPrevious,
material: materialCost,
};
const productNew = productData.products.map(function (rec) {
return rec.id === id ? productUpdated : rec;
});
console.log("productsNew:", productNew);
const productFullNew = {
...productData,
products: productNew,
};
setProductData(productFullNew);
}
};
return (
<div className="Card">
<h3> {productData.name} </h3>
<p>{productData.description}</p>
<table className="table">
<thead>
<tr>
<th scope="col">
<p>
<b> Material </b>
</p>
</th>
<th scope="col">
<p>
<b> Labor </b>
</p>
</th>
<th scope="col">
<p>
<b> Total</b>
</p>
</th>
</tr>
</thead>
<tbody id={`${productData.name}`}>
{productData.products.map((product) => {
return (
<Products
key={product.id}
product={product}
labor={3}
setMaterial={setMaterial}
setTotal={setTotal}
/>
);
})}
</tbody>
</table>
</div>
);
}
export default CompareCard;
这是子元素。它单独处理每个产品。
第一个calcTotal()用于设置原始总数。此调用有效,但当 material 稍后更改时,总计不会继续重新呈现。
import React, { useState, useEffect } from "react";
function Products({ product, labor, setMaterial, setTotal }) {
function setMaterialState(newMaterial) {
product.material = newMaterial;
}
function calcTotal() {
product.total = labor + product.material;
}
if (product.total === 0) {
calcTotal();
}
useEffect(() => {
setTotal(product.id, product.total);
}, [product.total]);
useEffect(() => {
setMaterial(product.id, product.material);
//setTotal(product.id, product.material + labor);
}, [product.material]);
function ProductMaterial() {
const [name, setName] = useState("");
function handleChange(e) {
setName(parseFloat(e.target.value));
setMaterialState(parseFloat(e.target.value));
setMaterial(product.id, product.material);
calcTotal();
setTotal(product.id, product.total);
}
return (
<input
type="number"
name="firstName"
onChange={handleChange}
value={product.material}
/>
);
}
return (
<tr key={product.name}>
<td>
<ProductMaterial product={product} />{" "}
<td id={`total-${product.id}`}>{product.total}</td>
</tr>
);
}
export default Products;
它不起作用,因为 setMaterial 和 setTotal 都有一个内部函数,但内部函数永远不会执行。
您应该删除函数 setTotalUpdate 和 setMaterialUpdate 来解决您的更新问题,如下所示。
function CompareCard({ type, labor }) {
const [productData, setProductData] = useState(data);
const setTotal = (id, total) => {
const productPrevious = productData.products.find(function (rec) {
return rec.id === id;
});
const productUpdated = {
...productPrevious,
total: total,
};
const productNew = productData.products.map(function (rec) {
return rec.id === id ? productUpdated : rec;
});
const productFullNew = {
...productData,
products: productNew,
};
setProductData(productFullNew);
};
const setMaterial = (id, materialCost) => {
const productPrevious = productData.products.find(function (rec) {
return rec.id === id;
});
const productUpdated = {
...productPrevious,
material: materialCost,
};
const productNew = productData.products.map(function (rec) {
return rec.id === id ? productUpdated : rec;
});
console.log("productsNew:", productNew);
const productFullNew = {
...productData,
products: productNew,
};
setProductData(productFullNew);
};
return (
<div className="Card">
<h3> {productData.name} </h3>
<p>{productData.description}</p>
<table className="table">
<thead>
<tr>
<th scope="col">
<p>
<b> Material </b>
</p>
</th>
<th scope="col">
<p>
<b> Labor </b>
</p>
</th>
<th scope="col">
<p>
<b> Total</b>
</p>
</th>
</tr>
</thead>
<tbody id={`${productData.name}`}>
{productData.products.map((product) => {
return (
<Products
key={product.id}
product={product}
labor={3}
setMaterial={setMaterial}
setTotal={setTotal}
/>
);
})}
</tbody>
</table>
</div>
);
}
export default CompareCard;