如何根据预加载数据的 checked/unchecked 输入设置不同的状态

How to set different states based on checked/unchecked inputs with pre-loaded data

我有两组数据来自 API、accountContacts 和 callReportContacts,如下所示:

const accountContacts = [
  {
    Id: "3SLS-003QZ",
    "First Name": "Lynne",
    "Last Name": "Froisland"
  },
  {
    Id: "3SLS-003QA",
    "First Name": "John",
    "Last Name": "Doe"
  },
  {
    Id: "3SLS-003QB",
    "First Name": "Jane",
    "Last Name": "Doe"
  },
  {
    Id: "3SLS-003RL",
    "First Name": "Curtis",
    "Last Name": "Shrestha"
  },
  {
    Id: "3SLS-003S1",
    "First Name": "Susan",
    "Last Name": "Simoncelli"
  }
];

const callReportContacts = [
  {
    Id: "3SLS-003RL",
    "First Name": "Curtis",
    "Last Name": "Shrestha",
    checked: true
  },
  {
    Id: "3SLS-003S1",
    "First Name": "Susan",
    "Last Name": "Simoncelli",
    checked: true
  }
];

现在,callReportContacts 默认没有 checked 属性。因此,我在设置状态之前将其添加到响应中。然后我将它们合并,以便 callReportContacts 中的项目替换 accountContacts 中的项目,如下所示:

useEffect(() => {
  setMergedContacts(
    accountContacts.map((contact) => {
      const item = callReportContacts.find(({ Id }) => Id === contact.Id);
      return item ? item : contact;
    })
  );
}, []);

然后我使用输入复选框组件呈现 mergedContacts,如果其设置为 true,则具有预先检查的状态,如下所示:

{mergedContacts.map(({ Id, 'First Name': firstName, 'Last Name': lastName, checked }) => {
    return (
      <ToggleOption
        contacts={contacts}
        setContacts={setContacts}
        deselectedContacts={deselectedContacts}
        setDeselectedContacts={setDeselectedContacts}
        key={Id}
        contactID={Id}
        label={firstName + ' ' + lastName}
        ischecked={checked}
      />
    )
  })
}

我想要的是两组状态,联系人和取消选择的联系人,它们将分别发布到各自的 API 端点。如果我 check/uncheck 一个未检查的输入,它应该是来自联系人状态的 added/removed 并且对于取消选择的联系人状态的预检查输入也是如此。这是 bare bones working link

在示例中,如果我 check/uncheck Lynne、John 或 Jane 他们应该 added/removed 来自联系人状态,如果我对 Curtis 或 Susan 做同样的事情,他们应该 added/removed 来自取消选择的联系人状态。

您可以利用 checked: true 来自 API 的数据。您已经将此数据存储在 mergedContacts 上 - 因此如果最初检查了此对象,您可以将其用作标志。这将在稍后使用,用于评估是否推送到 contactsdeselectedContacts.

话虽如此,我查看了您的 ToggleOption 组件,看起来您已经将该对象属性作为名为 ischecked 的 prop 传递了,此外,您没有进行变异它 - 让工作更轻松。

我所做的是将额外的道具传递给 ToggleOption 组件、deselectedContacts 状态和 setDeselectedContacts 状态 setter。之后,在 ToggleOption 输入的 onChange/onClick 事件中,我传递了 ischecked 属性,它会指示联系人是否最初被检查过。

return (
  <div className="toggle-option">
    <div onClick={() => handleToggle(ischecked)}>
      <input
        ref={toggleRef}
        data-id={contactID}
        onChange={() => handleToggle(ischecked)}
        ...

最后,在 handleToggle 处理程序上,我根据最初是否检查了联系人,对需要更新的状态设置了条件,再次 - 我使用了 ischecked 属性.

const handleToggle = (ischecked) => {
  setCheckedState((prevState) => !checkedState);

  const item = {
    Id: toggleRef.current.getAttribute("data-id")
  };

  if (ischecked) {
    if (deselectedContacts.map((e) => e["Id"]).includes(item["Id"])) {
      setDeselectedContacts(
        deselectedContacts.filter((e) => e["Id"] !== item["Id"])
      );
    } else {
      setDeselectedContacts([...deselectedContacts, item]);
    }
  } else {
    if (contacts.map((e) => e["Id"]).includes(item["Id"])) {
      setContacts(contacts.filter((e) => e["Id"] !== item["Id"]));
    } else {
      setContacts([...contacts, item]);
    }
  }
};

代码沙盒:https://codesandbox.io/s/charming-brown-6rczt?file=/src/App.js