状态更改后失去对输入的关注
Focus on input is lost after state change
每次我重新渲染和更新状态时,我的输入框都会失去焦点。我想知道如何在用户点击离开之前将焦点保持在文本框上。
我的应用程序输入每个产品的 material 成本并计算该产品的总和。我希望在更新输入后重新呈现组件以显示更新后的总数。貌似每次material cost变化的时候总算出来了,state也在更新,但是用户每次都得手动重新选择输入框,因为焦点没了。
这是我的应用程序的屏幕截图(为简单起见,删除了 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 函数几乎相同(我确信有一种方法可以重构它)。用户在元素中键入数字后,将调用这两个函数。
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,
};0
//calculate new final totals
let newFinalTotal = 0;
let newFinalMaterial = 0;
let newFinalTime = 0;
productFullNew.products.map((product) => {
newFinalTotal += product.total;
newFinalMaterial += product.material;
newFinalTime += product.time;
});
productFullNew.finalTotal.total = newFinalTotal;
productFullNew.finalTotal.material = newFinalMaterial;
productFullNew.finalTotal.time = newFinalTime;
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;
});
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;
这是子元素。它单独处理每个产品。
元素住在这里。
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;
我发现 Sergi Juanati 回答了一个类似的 Whosebug 问题,它对我有用 In React ES6, why does the input field lose focus after typing a character?
我将保存输入 return 语句的函数切换为以下语法:
const Products = ({ product, labor, setMaterial, setTotal }) => {};
以及对此函数的调用:
{ProductMaterial({ product: product })}
每次我重新渲染和更新状态时,我的输入框都会失去焦点。我想知道如何在用户点击离开之前将焦点保持在文本框上。
我的应用程序输入每个产品的 material 成本并计算该产品的总和。我希望在更新输入后重新呈现组件以显示更新后的总数。貌似每次material cost变化的时候总算出来了,state也在更新,但是用户每次都得手动重新选择输入框,因为焦点没了。
这是我的应用程序的屏幕截图(为简单起见,删除了 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 函数几乎相同(我确信有一种方法可以重构它)。用户在元素中键入数字后,将调用这两个函数。
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,
};0
//calculate new final totals
let newFinalTotal = 0;
let newFinalMaterial = 0;
let newFinalTime = 0;
productFullNew.products.map((product) => {
newFinalTotal += product.total;
newFinalMaterial += product.material;
newFinalTime += product.time;
});
productFullNew.finalTotal.total = newFinalTotal;
productFullNew.finalTotal.material = newFinalMaterial;
productFullNew.finalTotal.time = newFinalTime;
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;
});
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;
这是子元素。它单独处理每个产品。
元素住在这里。
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;
我发现 Sergi Juanati 回答了一个类似的 Whosebug 问题,它对我有用 In React ES6, why does the input field lose focus after typing a character?
我将保存输入 return 语句的函数切换为以下语法:
const Products = ({ product, labor, setMaterial, setTotal }) => {};
以及对此函数的调用:
{ProductMaterial({ product: product })}