You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中对象数组添加元素时状态丢失及报错问题求助

Fixing React Object Array State Update Issues

Let's break down what's going wrong with your state management and fix it step by step:

Key Problems Identified

  1. Incorrect Initial State: You initialized estimate as an empty array [], but your desired structure is an object with an items array property. This mismatch breaks value access and state updates.
  2. Broken State Update Logic: When updating cost or service, you're replacing the entire items array with a single object instead of preserving existing entries and only updating the target one.
  3. Wrong Value Access: You're trying to access estimate?.items?.["cost"]?.[i]—this assumes items is an object with a cost array, but items is actually an array of objects where each object has cost and service keys.

Corrected Code Implementation

Here's the fixed version with detailed explanations:

import { useState } from 'react';
// Import your Syncfusion components here

const YourComponent = () => {
  // 1. Fix initial state to match your desired structure
  const [estimate, setEstimate] = useState({ items: [] });
  const [numServices, setNumServices] = useState(0);

  return (
    <form>
      {[...Array(numServices)].map((_, i) => {
        return (
          <div key={i} className="flex justify-between">
            <div>
              <NumericTextBoxComponent
                format="c2"
                name={`cost-${i}`}
                // 2. Correct value access: get cost from the i-th object in items array
                value={estimate.items[i]?.cost}
                change={(e) => {
                  // 3. Properly update state without overwriting existing items
                  setEstimate(prevState => {
                    const updatedItems = [...prevState.items];
                    // Ensure the i-th index exists, or create a new object if not
                    updatedItems[i] = { ...updatedItems[i], cost: e.value };
                    return { ...prevState, items: updatedItems };
                  });
                }}
                placeholder='Price'
                floatLabelType="Auto"
                data-msg-containerid="errorForCost"
              />
            </div>
            <div>
              <DropDownListComponent
                showClearButton
                fields={{ value: "id", text: "service" }}
                name={`service-${i}`}
                // 2. Correct value access: get service from the i-th object in items array
                value={estimate.items[i]?.service}
                change={(e) => {
                  // 3. Properly update state without overwriting existing items
                  setEstimate(prevState => {
                    const updatedItems = [...prevState.items];
                    // Map selected id to service text (adjust based on your data structure)
                    const selectedService = estimateData?.services.find(s => s.id === e.value)?.service || e.value;
                    updatedItems[i] = { ...updatedItems[i], service: selectedService };
                    return { ...prevState, items: updatedItems };
                  });
                }}
                id={`service-${i}`}
                floatLabelType="Auto"
                data-name={`service-${i}`}
                dataSource={estimateData?.services}
                placeholder="Service"
                data-msg-containerid="errorForLead"
              />
              <div id="errorForLead" />
            </div>
          </div>
        );
      })}
      {/* 4. Add default empty object to items when clicking Add */}
      <button onClick={() => {
        setNumServices(prev => prev + 1);
        setEstimate(prev => ({
          ...prev,
          items: [...prev.items, { cost: 0, service: "" }]
        }));
      }}>Add</button>
    </form>
  );
};

export default YourComponent;

What Each Fix Does

  • Initial State Fix: Starting with { items: [] } aligns your state with the structure you need, so you can properly access and update the items array.
  • State Update Logic: Using the functional update form (setEstimate(prevState => ...)) ensures you're always working with the latest state. We create a copy of the items array, update the specific index, then return the new state—this preserves all existing items while modifying only the one you need.
  • Value Access: estimate.items[i]?.cost correctly targets the cost property of the i-th object in the items array, matching your desired data structure.
  • Add Button Enhancement: Now when you click "Add", we not only increment numServices but also add a default empty object to items, ensuring the new rendered input has a corresponding entry in the state array.

Additional Notes

If your DropDownListComponent returns the id of the selected service instead of the text (as per your fields={{ value: "id", text: "service" }}), we added logic to map the selected id back to the service text using estimateData?.services.find(). Adjust this part if your data structure or needs are different.

内容的提问来源于stack exchange,提问作者mattr534

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 18:40:39