如何在React中动态更新状态数组?

时间:2019-05-03 12:17:08

标签: javascript reactjs

我具有以下组件,该组件的功能可以在表单中动态添加New元素。我有一个按钮,当单击该按钮时,将添加一个新的表单字段。现在,我需要将此新字段的值保持在新状态,并将其发送到API。为了发送所有新字段,我计划将单个状态设置为数组,并在输入新字段值后推送它们。在添加了几个新字段之后,我需要像这样的东西,

this.state.other [
   {
      description: "field 1 description",
      amount: "120$"
   },
   {
      description: "field 2 description",
      amount: "180$"
   },
   {
      description: "field 3 description",
      amount: "156$"
   },
]

这是我到目前为止尝试过的:

let dataId = 0;

class ClientIntakeModal extends Component {
    constructor(props) {
        super(props);

        this.allOtherCosts = [];

        this.state = {
            otherCosts: this.allOtherCosts,
            other: [],
        }
        this.otherDescInputHandle = this.otherDescInputHandle.bind(this);
    }

    appendData = () => {
        dataId = dataId + 1;
        this.allOtherCosts.push(
            <div className="halfWidth jobCostMain" key={dataId}>
                <div>
                    <div className="jobDescAdded">
                        <TextField
                            id={'costDescription'}
                            name={'description'}
                            type="text"
                            value={this.state.other.description}
                            onChange={this.otherDescInputHandle}
                        />
                    </div>
                    <div className="jobCostAdded">
                        <TextField
                            id={'costAmount'}
                            name={'amount'}
                            type="number"
                            value={this.state.other.amount}
                            onChange={this.otherDescInputHandle}
                        />
                    </div>
                </div>
            </div>
        );
        this.setState({
            otherCosts: this.allOtherCosts
        });
    }

    otherDescInputHandle(event) {
        const target = event.target;
        const value = target.value;
        const name = target.name;

        this.setState({
            other: [
                ...this.state.other,
                {
                    [name]:value
                },
            ]
        });
    }

    render() {
      return(
           <div>
             <div id="addNewUser" className="addNewUser" onClick={this.appendData}>
                 <span>+</span>
             </div>
             {this.allOtherCosts}
           </div>
      )
    }
}

问题是,我收到如下消息

this.state.other [
   {
      description: "f",
   },
   {
      description: "fi",
   },
   {
      description: "fie",
   },
   {
      description: "fiel",
   },
]

如何在这里获得正确的状态?

2 个答案:

答案 0 :(得分:0)

我对您的代码有一些考虑,这将使他更好。 otherDescInputHandle 函数,使用解构,如下所示:

const { target, value, name } = event;

然后执行以下操作:

const { other } = this.state;
/* your ideia */
this.setState({ other });

在您的 appendData 函数中,在dataId中获取数组的长度

dataId = this.allOtherCosts.length;

并在文本字段的onChange中,传递事件和dataId

onChange={e => this.otherDescInputHandle(e, dataId)}

因此,在 otherDescInputHandle 中,您具有字段在数组上的位置,并且当您更改值时,可以访问数组的正确位置:

const { other } = this.state;
other[dataId].description = value;

尝试这个想法。我想这会解决您的问题。

并且,请尝试仅使用状态变量并对其进行操作。完全可能无需使用 this.allOtherCosts = [];

即可解决您的问题

答案 1 :(得分:0)

通常,我建议使用以下方法来更新集合的不可变项。对于项目使用id很重要,它可以是动态生成的唯一ID。

class App extends React.Component {
  state = {
    someArray: [
      { id: 1, value: 'a' },
      { id: 2, value: 'b' },
      { id: 3, value: 'c' }
    ]
 }

  setValue = (id, value) => {
    this.setState(prevState => ({
      someArray: prevState.someArray.map(item => (
        id === item.id ? { ...item, value } : item
      ))
    }))
  }
  
  render(){
    return (
      <div>
        <ul>
          {this.state.someArray.map(({value}) => <li>{value}</li>)}
        </ul>
        <button onClick={() => this.setValue(2, 'foo')}>Set value</button>
      </div>
    )

  }
}

ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>