为了账号安全,请及时绑定邮箱和手机立即绑定

从 div 数组中删除元素时的奇怪行为(React Hooks)

从 div 数组中删除元素时的奇怪行为(React Hooks)

月关宝盒 2022-06-05 10:56:22
从 div 数组中删除元素时,我正在努力理解一种奇怪的行为。我想要做的是创建一个代表购买列表的 div 数组。每个购买都有一个删除按钮,该按钮必须只删除单击的那个。发生的情况是,当在购买 x 上单击删除按钮时,所有索引大于 x 的元素都将被删除。任何帮助将不胜感激,包括语法建议:)import React, { useState } from "react";const InvestmentSimulator = () => {  const [counter, increment] = useState(0);  const [purchases, setPurchases] = useState([    <div key={`purchase${counter}`}>Item 0</div>  ]);  function addNewPurchase() {    increment(counter + 1);    const uniqueId = `purchase${counter}`;    const newPurchases = [      ...purchases,      <div key={uniqueId}>        <button onClick={() => removePurchase(uniqueId)}>delete</button>        Item number {uniqueId}      </div>    ];    setPurchases(newPurchases);  }  const removePurchase = id => {    setPurchases(      purchases.filter(function(purchase) {        return purchase.key !== `purchase${id}`;      })    );  };  const purchasesList = (    <div>      {purchases.map(purchase => {        if (purchases.indexOf(purchase) === purchases.length - 1) {          return (            <div key={purchases.indexOf(purchase)}>              {purchase}              <button onClick={() => addNewPurchase()}>add</button>            </div>          );        }        return purchase;      })}    </div>  );  return <div>{purchasesList}</div>;};export default InvestmentSimulator;
查看完整描述

2 回答

?
慕斯709654

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,而不是与其在列表中的位置相关。


查看完整回答
反对 回复 2022-06-05
?
HUWWW

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>

  );


查看完整回答
反对 回复 2022-06-05
  • 2 回答
  • 0 关注
  • 155 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信