简体   繁体   English

如何使用复选框更新 useState 中的数组

[英]How to update an array inside a useState with a checkbox

I am trying to create a form where each item checked is pushed or removed from the useState-product[].我正在尝试创建一个表单,其中将检查的每个项目从 useState-product[] 中推送或删除。

What I mean is the following:我的意思是:

After a request a table of Hammers is generated automatically.请求后会自动生成一个锤子表。

<table>
  <thead>
    <tr>
      <th scope="col">Use</th>
      <th scope="col">ID</th>
      <th scope="col">Length</th>
      <th scope="col">Width</th>
      <th scope="col">Weight</th>
    </tr>
  </thead>
  <tbody>
    {response &&
      response.map((element) => (
        <tr key={element._id}>
          <th>
            <input type="checkbox" value={element._id} />
          </th>
          <th>{element._id}</th>
          <th>{element.length}</th>
          <th>{element.width}</th>
          <th>{element.weight}</th>
        </tr>
      ))}
  </tbody>
</table>

And this table is part of a form that will be sent with other information including an array of Hammers and I am saving all this form data in the following useState.此表是将与其他信息(包括锤子数组)一起发送的表单的一部分,我将所有此表单数据保存在以下 useState 中。

interface Order {
  date: Date,
  hammers: string[],
  purchase_order: number,
}

const [form, setForm] = useState <Order> ({
  date: new Date(),
  hammers: [],
  purchase_order: 0
});

Im updating date and purchase_order this way:我以这种方式更新日期和购买订单:

const handleForm = (e: React.ChangeEvent<HTMLInputElement>) => {
  setForm({ ...form, [e.target.id]: e.target.value });
};

So my question is, how do I update the hammer array with the _id each time a hammer is checked or unchecked from the table?所以我的问题是,每次从表中选中或取消选中锤子时,如何使用 _id 更新锤子数组?

Example hammers[ ]: if 2 are checked示例 hammers[ ]:如果选中 2

hammers = ["639761fff0bbbac77d77e44d", "6397af36a3ead940becb8805"]锤子 = ["639761fff0bbbac77d77e44d", "6397af36a3ead940becb8805"]

There are two problems you have to solve.您必须解决两个问题。 The first is setting up your events correctly, and the second is actually updating the array correctly.第一个是正确设置事件,第二个是正确更新数组。

When we look at your event handler:当我们查看您的事件处理程序时:

const handleForm = (e: React.ChangeEvent<HTMLInputElement>) => {
  setForm({ ...form, [e.target.id]: e.target.value });
};

We see that you're looking for an ID ( e.target.id ), but looking at your input:我们看到您正在寻找 ID ( e.target.id ),但查看您的输入:

<input type="checkbox" value={element._id} />

There is no id attribute to be found.找不到id属性。 There's also no way for this function to even fire when the input is checked or unchecked.当检查输入或未选中输入时,此功能也无法发射。 So let's fix those two issues first:所以让我们先解决这两个问题:

<input
  id={element._id}
  type="checkbox"
  onChange={handleForm}
/>

You'll notice I didn't bother to add a value to the input, so this is an uncontrolled input.您会注意到我没有费心向输入添加value ,因此这是一个不受控制的输入。

Now that your HTML (JSX) is correct, we can look at the event handler itself.现在您的 HTML (JSX) 是正确的,我们可以查看事件处理程序本身。 Your initial state looks like this:您的初始状态如下所示:

const [form, setForm] = useState <Order> ({
  date: new Date(),
  hammers: [],
  purchase_order: 0
});

So you need to have your function return a similar shape, or your state will get all out of whack once you start checking some boxes.所以你需要让你的函数返回一个相似的形状,否则一旦你开始选中一些框,你的状态就会变得一团糟。 Your current code spreads the existing state object and then adds a new key with the checkbox ID.您当前的代码传播现有的状态对象,然后添加一个带有复选框 ID 的新键。 What you need is to do instead is spread the date and purchase_order values (or update them, if appropriate — you tell me) and then manipulate the hammers value.您需要做的是传播datepurchase_order值(或者更新它们,如果合适的话——您告诉我),然后操纵hammers值。

Also, the value of a checkbox is just the string 'on' .此外,复选框的value只是字符串'on' You should use event.target.checked instead.您应该改用event.target.checked

So:所以:

const handleForm = (e: React.ChangeEvent<HTMLInputElement>) => {
  const {checked, id} = event.target;
  const {hammers} = form;
  const copyOfHammers = [...hammers];

  if (checked) {
    // add a new id to the array
    copyOfHammers.push(id);
  } else {
    // remove the id from the array
    copyOfHammers.splice(copyOfHammers.indexOf(id), 1);
  }

  return {
    ...form,
    hammers: copyOfHammers,
  };
};

This is example code, but you can modify it as needed.这是示例代码,但您可以根据需要对其进行修改。 This also isn't the only way to potentially add or remove an item from an array.这也不是可能从数组中添加或删除项目的唯一方法。

What you need is to check if e.target.value is true or false and add or remove the elementId from your array.您需要做的是检查 e.target.value 是真还是假,并从数组中添加或删除 elementId。 I suggest handleForm to go like this:我建议 handleForm 像这样:

const handleForm = (e: React.ChangeEvent<HTMLInputElement>, elementId) => {
    setForm(form => {
        let newFormState = form
        if (event.target.checked) {
            newFormState.hammers = [...form.hammers, elementId] 
        } else {
             newFormState.hammers = form.hammers.filter(f => f !== elementId)
        }
     return newFormState
};

So basically we are creating a copy of your form, overwriting your form.hammers state according to event.target.checked, and returning the newState to your reducer.所以基本上我们正在创建您的表单的副本,根据 event.target.checked 覆盖您的 form.hammers 状态,并将 newState 返回给您的 reducer。

I like to use setForm as a callback function like we did here, which means instead of giving the new state, saying "hey... give me the current state (in this case "form", and with that as callback (noted by the arrow function) I would like to return you the new state.我喜欢使用 setForm 作为回调函数,就像我们在这里所做的那样,这意味着不是给出新状态,而是说“嘿......给我当前状态(在本例中为“form”,并将其作为回调(由箭头函数)我想返回给你新的状态。

This can be done with less lines of code, but for clearence I have done it in a more didatic way.这可以用更少的代码行来完成,但为了清楚起见,我以一种更说教的方式完成了它。

Now... input should receive现在......输入应该收到

<input onClick={(e) => handleForm(e, element._id)} ...and our other props />

because we are passing down the element._id to the function.因为我们将 element._id 传递给函数。

Cheers.干杯。

 const handleChecked = id => e => {
   if(e.target.checked){
    setForm({ ...form, hammers: [...form.hammers, id] })
  } else{
    setForm({ ...form, hammers: form.hammers.filter(e => e !== id) })
  }};

This should probably do it with few tweaks这应该可以通过一些调整来完成

const handleForm = (e: React.ChangeEvent<HTMLInputElement>) => {
  if (e.target.checked) {
    setForm({ ...form, hammers: [...form.hammers, e.target.value] });
  } else {
    setForm({
      ...form, hammers: form.hammers.filter((element) => element !== e.target.value),
    });
  }
};

And the checkbox和复选框

onChange={handleForm}

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

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