如何使用 useState 钩子更新现有的对象数组(向数组中添加一个新对象)?

时间:2020-12-22 15:06:11

标签: javascript reactjs typescript react-redux react-hooks

我有一个 onChange 处理程序,我可以使用它来编辑具有输入字段的某些对象。

onChange 处理程序如下所示:

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

API 为人员(对象数组)返回以下内容:

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

我的 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 });
  }
};

我的模板看起来像这样(只是用于创建具有 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>

不幸的是,它不能那样工作。

  1. 第一个输入框只实现第一个字母,之后整个组件消失

  2. 如果我操纵它以使组件不消失,则输入字段的值不会更新(这可能是因为我设置了 value = ' '。我不知道我还应该提供什么)。

  3. 如果我在 1. 中提到的第一个字母之后控制台记录人员,则对象数组更新如下:

    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"
    

但我的目标是当我创建一个新人时,对象应该更新如下:

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"}

我在这里做错了什么?

2 个答案:

答案 0 :(得分:2)

尝试不要在对象内部传播列表,而是传播列表并添加对象,这也是因为当您呼叫新人时没有提供索引:

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}]
      }
   }
};

答案 1 :(得分:0)

不幸的是,我无法使用建议的方法解决它。但我以不同的方式做到了。

我调整了 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);
  }
};

相反,我现在直接在文本字段的 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());

我的文本字段现在看起来像这样:

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

我还创建了一个提交处理程序,在其中更新状态并随后清空表单字段。

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

让我知道这个解决方案是否也可以。

相关问题