简体   繁体   English

如何使用 useState 挂钩更新现有的对象数组(将新的 object 添加到数组中)?

[英]How to update an existing array of objects (add a new object to the array) with the useState hook?

I have an onChange handler with which I can edit certain objects with input fields.我有一个 onChange 处理程序,我可以使用它编辑带有输入字段的某些对象。

The onChange handler looks like this: onChange 处理程序如下所示:

// First I get the current state
const [persons, setPersons] = useState(service.persons);

The API returns the following for persons (an array of objects): API 为人员(对象数组)返回以下内容:

contacts (2) [{…}, {…}]
0: {person_company: "Google", person_name: "John Doe"}
1: {person_company: "Facebook", person_name: "Jane Doe"}

My onChange handler looks like this (..first part of the if statement for editing the given persons works perfectly, but the else statement for creating a new person doesn't):我的 onChange 处理程序看起来像这样(.. 用于编辑给定人员的 if 语句的第一部分可以完美运行,但用于创建新人员的 else 语句则不能):

const updatePersons = (e: any, index?: number) => {
  if (index !== undefined) {
    const updatedPersons = [...persons];
    updatedPersons[index][e.target.name] = e.target.value;
    setPersons(updatedPersons);
  } else {
    setPersons({ ...persons, [e.target.name]: e.target.value });
  }
};

My template looks like this (just empty input fields for creating a new person with a person_company and person_name):我的模板看起来像这样(只是空的输入字段用于创建一个带有 person_company 和 person_name 的新人):

<InputContainer>
  <p>New person</p>
  <InputWrapper>
    <TextField
      type="text"
      label="Person company"
      name='person_company'
      value=' '
      onChange={e => updatePersons(e)}
    />
  </InputWrapper>
  <InputWrapper>
    <TextField
      type="text"
      label="Person name"
      name="person_name"
      value=' '
      onChange={e => updatePersons(e)}
    />
  </InputWrapper>
</InputContainer>

Unfortunately, it doesn't work that way.不幸的是,它不是那样工作的。

  1. Only the first letter is realized in the first input field and the whole component disappears afterwards在第一个输入字段中仅实现第一个字母,然后整个组件消失

  2. If I manipulate it so that the component does not disappear, the value of the input field is not updated (this is probably because I set value = ' '. I have no idea what else I should provide).如果我对其进行操作以使组件不会消失,则输入字段的值不会更新(这可能是因为我设置了 value = ' '。我不知道我还应该提供什么)。

  3. If I console log persons after the first letter as mentioned in 1., the array of object is updated as follows:如果我在 1. 中提到的第一个字母之后控制台记录人员,则 object 的数组更新如下:

     contacts {0: {…}, 1: {…}, company_name: " t"} 0: {person_company: "Google", person_name: "John Doe"} 1: {person_company: "Facebook", person_name: "Jane Doe"} person_company: " t"

But my goal is that the object should be updated as follows when I create a new person:但我的目标是当我创建一个新人时,object 应该更新如下:

contacts (3) [{…}, {…}, {…}]
0: {person_company: "Google", person_name: "John Doe"}
1: {person_company: "Facebook", person_name: "Jane Doe"}
2: {person_company: "Amazon", person_name: "Max Mustermann"}

What am I doing wrong here?我在这里做错了什么?

try this dont spread a list inside of object, and instead spread a list and add object, also because when you call a new person there is no index provided:试试这个不要在 object 内传播列表,而是传播一个列表并添加 object,也是因为当你打电话给新人时没有提供索引:

const updatePersons = (e: any, index?: number) => {
  if (index !== undefined) {
    const updatedPersons = [...persons];
    updatedPersons[index][e.target.name] = e.target.value;
    setPersons(updatedPersons.map((person)=>({...person,new:false})));
  } else {
      const lastPerson = persons.slice(-1)[0];
      if (lastPerson.new){
          setPersons([...persons.slice(0,-1), {...lastPerson ,[e.target.name]:e.target.value}]);
      } else {
          setPersons([...persons,{[e.target.name]:e.target.value , new:true}]
      }
   }
};

Unfortunately, I couldn't solve it using the approaches suggested.不幸的是,我无法使用建议的方法解决它。 But I did it in a different way.但我以不同的方式做到了。

I adapted the updatePersons method, which now only processes the cases with an ID (so no else block anymore).我调整了 updatePersons 方法,该方法现在只处理带有 ID 的案例(因此不再有 else 块)。

const updatePersons = (e: any, index?: number) => {
  e.preventDefault(); // is this needed here?
  if (index !== undefined) {
    const updatedPersons = [...persons];
    updatedPersons[index][e.target.name] = e.target.value;
    setPersons(updatedPersons);
  }
};

Instead, I now do everything directly in the onChange handler of the textfields to create a new person.相反,我现在直接在文本字段的 onChange 处理程序中执行所有操作来创建一个新人。

// I created another useState hook for the new Person 
// ..and provided an initial state (empty strings) by instantiating a new Person:

const [newPerson, setNewPerson] = useState(new Person());

My textfields now look like this:我的文本字段现在看起来像这样:

  <InputWrapper>
    <TextField
      type="text"
      label="Person name"
      name="person_name"
      value=' '
      onChange={e => setNewPerson({ ...newPerson, [e.target.name]: e.target.value })}
    />
  </InputWrapper>

I have also created a submit handler in which I update the state and empty the form fields afterwards.我还创建了一个提交处理程序,在其中更新 state 并随后清空表单字段。

  const submitHandler = (e: any) => {
    e.preventDefault(); // is this needed here?
    setPersons([...persons, newPerson]);
    setNewPerson(new Person()); // Empty the form fields
  };

Let me know if this solution is also ok.让我知道这个解决方案是否也可以。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM