我正在尝试添加到在React中分成两个输入的对象数组

问题描述 投票:0回答:1

所以我有一个对象数组,其中键是“成本”和“服务”,称为估计。您可以通过单击“添加”来添加到数组,这会向数组添加新索引 (i)。问题是在第一个周期中,我得到了一个很好的数组 {'cost': 2500, 'service': "commercial Cleaning"} (imgSet-1),但是当我添加另一个项目时,它完全删除了该数组并仅设置了其中一个嵌套对象的键和值。 (imgSet-2)。这是我在保存状态后寻找的结果(imgSet-3),我尝试使用@RubenSmn 方法,但随后收到此错误。 (imgSet-4)

imgSet-1 ********* 添加初始服务 初始服务添加的结果


imgSet-2 ********* 添加第二个服务 第二次添加服务的结果


imgSet-3 ********* Finale rendered outcome


imgSet-4 ********* Error after trying dif approach


下面是页面部分的代码,您可以在其中添加服务和文本输入的输出。

const [estimate, setEstimate] = useState([]);

{[...Array(numServices)].map((e, i) => {
            return (
              <div key={i} className="flex justify-between">
                <div>
                  <NumericTextBoxComponent
                    format="c2"
                    name={`cost-${i}`}
                    value={estimate?.items?.["cost"]?.[i]}
                    change={(e) =>
                      setEstimate({ ...estimate, items: [{...estimate?.items?.[i],cost: e?.value}]})
                    }
                    placeholder='Price'
                    floatLabelType="Auto"
                    data-msg-containerid="errorForCost"
                  />
                </div>
                <div>
                  <DropDownListComponent
                    showClearButton
                    fields={{ value: "id", text: "service" }}
                    name={`service-${i}`}
                    value={estimate?.items?.["service"]?.[i]}
                    change={(e) =>
                      setEstimate({ ...estimate, items: [{...estimate?.items?.[i],service: e?.value}]})
                    }
                    id={`service-${i}`}
                    floatLabelType="Auto"
                    data-name={`service-${i}`}
                    dataSource={estimateData?.services}
                    placeholder="Service"
                    data-msg-containerid="errorForLead"
                  ></DropDownListComponent>
                  <div id="errorForLead" />
                </div>
              </div>
            );
          })}
        </form>
        <button onClick={() => setNumServices(numServices + 1)}>Add</button>

我尝试了多种不同的扩展运算符,但我似乎无法让它工作。我的预期结果是:

estimate:{
  items: [
    {'cost': 2500, 'service': 'Commercial Clean'},
    {'cost': 500, 'service': 'Bathroom Clean'},
    {'cost': 180, 'service': 'Apartment Clean'},
    {etc.}
]
}
javascript reactjs object next.js spread-syntax
1个回答
0
投票

初始状态是一个数组,它不是您在

change
处理程序中设置的对象。你可以有这样的初始状态。

const [estimate, setEstimate] = useState({ items: [] });

设置新状态时,您不会添加回状态的项目。

setEstimate({
  ...estimate,
  items: [{ ...estimate?.items?.[i], cost: e?.value }],
  // should be something like
  // items: [...estimate.items, { ...estimate.items?.[i], cost: e?.value }],
});

但是你不能这样做,因为每次更改值时它都会在你的 items 数组中创建一个新对象。

我制作了这个动态

handleChange
函数,您可以使用它来更改状态。第一个 if 语句是检查 itemIndex 是否已在 items 数组中。如果没有,请使用
propertyName
value

创建一个新项目
const handleChange = (e, itemIndex, propertyName) => {
  const newValue = e?.value;

  setEstimate((prevEstimate) => {
    if (prevEstimate.items.length <= itemIndex) {
      const newItem = { [propertyName]: newValue };
      return {
        ...prevEstimate,
        items: [...prevEstimate.items, newItem]
      };
    }

    // loop over old items
    const newItems = [...prevEstimate.items].map((item, idx) => {
      // if index' are not the same just return the old item
      if (idx !== itemIndex) return item;
      // else return the item with the new service
      return { ...item, [propertyName]: newValue };
    });

    return {
      ...prevEstimate,
      items: newItems,
    };
  });
};

对于服务下拉列表,您可以对成本执行相同的操作,只需更改属性名称

<DropDownListComponent
  ...
  value={estimate.items[i]?.service}
  change={(e) => handleChange(e, i, "service")}
  ...
></DropDownListComponent>

在这里查看简化版实时版本

© www.soinside.com 2019 - 2024. All rights reserved.