2 回答
TA贡献1840条经验 获得超5个赞
您的代码存在几个问题,因此我将一次解决一个问题:
不要将 JSX 存储在 state 中
State 用于存储可序列化的数据,而不是 UI。您可以存储数字、布尔值、字符串、数组、对象等……但不要存储组件。
保持 JSX 简单
您返回的 JSX 有点复杂。您正在映射,但如果是最后一次购买purchases,则还会返回一个按钮。add添加按钮与映射购买无关,因此单独定义:
return (
<div>
// Map purchases
{purchases.map(purchase => (
// The JSX for purchases is defined here, not in state
<div key={purchase.id}>
<button onClick={() => removePurchase(purchase.id)}>
delete
</button>
Item number {purchase.id}
</div>
))}
// An add button at the end of the list of purchases
<button onClick={() => addNewPurchase()}>add</button>
</div>
)
由于我们不应该将 JSX 存储在 state 中,return 语句就是我们将 state 值转换为 JSX 的地方。
不要给 setter 函数起混淆的名字。
您已经创建了一个状态变量counter,并命名了 setter 函数increment。这是误导 - 该函数increment不会增加计数器,它会设置计数器。如果我调用increment(0),计数不会增加,它被设置为 0。
与命名设置器函数保持一致。在 React 社区中公认的最佳实践是 setter 函数与它设置的变量具有相同的名称,并以单词 "set" 为前缀。换句话说,你的状态值是counter,所以你的 setter 函数应该被调用setCounter。这准确且描述了该函数的作用:
const [counter, setCounter] = useState(0)
状态是异步更新的——不要同步处理
在addNewPurchase函数中,您有:
increment(counter + 1)
const uniqueId = `purchase${counter}`
这不会按您期望的方式工作。例如:
const [myVal, setMyVal] = useState(0)
const updateMyVal = () => {
console.log(myVal)
setMyVal(1)
console.log(myVal)
}
考虑上面的例子。第一个console.log(myVal)将登录0到控制台。您希望第二个console.log(myVal)记录什么?您可能会期望1,但它实际上0也会记录。
在函数完成执行并且组件重新渲染之前,状态不会更新,因此 的值myVal永远不会在函数的中途改变。整个功能保持不变。
在您的情况下,您正在创建一个具有旧值的ID counter。
组件
这是您的组件的更新版本:
const InvestmentSimulator = () => {
// Use sensible setter function naming
const [counter, setCounter] = useState(0)
// Don't store JSX in state
const [purchases, setPurchases] = useState([])
const addNewPurchase = () => {
setCounter(prev => prev + 1)
setPurchases(prev => [...prev, { id: `purchase${counter + 1}` }])
}
const removePurchase = id => {
setPurchases(prev => prev.filter(p => p.id !== id))
}
// Keep your JSX simple
return (
<div>
{purchases.map(purchase => (
<div key={purchase.id}>
<button onClick={() => removePurchase(purchase.id)}>
delete
</button>
Item number {purchase.id}
</div>
))}
<button onClick={() => addNewPurchase()}>add</button>
</div>
)
}
最后的想法
即使进行了这些更改,该组件仍需要进行一些重新设计。
例如,使用计数器创建唯一 ID 不是一个好习惯。如果计数器被重置,项目将共享相同的 ID。我希望这些项目中的每一个最终都将存储更多的数据,而不仅仅是一个 ID,因此为每个项目提供一个与项目相关的唯一 ID,而不是与其在列表中的位置相关。
TA贡献1874条经验 获得超12个赞
永远不要使用数组的索引作为键。查看这篇文章了解更多相关信息。如果你想使用 index 做一些我在下面做的事情。
const purchasesList = (
<div>
{purchases.map((purchase, i) => {
const idx = i;
if (purchases.indexOf(purchase) === purchases.length - 1) {
return (
<div key={idx}>
{purchase}
<button onClick={() => addNewPurchase()}>add</button>
</div>
);
}
return purchase;
})}
</div>
);
添加回答
举报