【问题标题】:How to update an existing array of objects (add a new object to the array) with the useState hook?如何使用 useState 挂钩更新现有的对象数组(向数组中添加新对象)?
【发布时间】:2020-12-22 15:06:11
【问题描述】:

我有一个 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"}

我在这里做错了什么?

【问题讨论】:

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


    【解决方案1】:

    试试这个不要在对象内传播列表,而是传播一个列表并添加对象,也是因为当你打电话给一个新人时,没有提供索引:

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

    【讨论】:

    • 使用这种方法,它为每次击键添加一个新对象,在 person_company 输入字段中键入“test”后我得到以下内容(并且输入字段中的值仍然没有更新):@ 987654321@
    • 您还需要在调用onChange={e =&gt; updatePersons(e)} 所以onChange={e =&gt; updatePersons(e,index)} 时提供索引,或者即使在增加列表大小后也需要考虑其他方式来保持“新人”索引跨度>
    • 如果一切顺利,请告诉我...祝你好运
    • 不幸的是,这种方法不起作用。但我以不同的方式解决了它——我调整了 updatePersons 方法,现在它只处理带有 ID 的案例(所以不再阻塞)。相反,我现在直接在文本字段的 onChange 处理程序中执行所有操作来创建一个新人。我还创建了一个 submitHandler,我在其中更新状态并在之后清空表单字段。我将发布该方法作为答案。让我知道该解决方案是否也可以接受。
    • 祝你好运!我看不出有理由发布答案,但如果你愿意,那就去吧..
    【解决方案2】:

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

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

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

    【讨论】:

    • 是的:)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-09
    • 1970-01-01
    • 2020-07-27
    • 2021-10-18
    相关资源
    最近更新 更多