子组件中的第一次点击在父组件 React 中未定义

First click in child component is undefined in parent component React

我想在一个简单的联系人管理器应用程序中实现“单击时删除联系人”功能,我正在制作这个应用程序来学习 React,但它有很多问题。 我第一次单击要删除的项目时,它什么也没做,当再次单击时,它会删除前一个。我刚开始学习 React,不知道为什么会这样,有人可以帮忙吗?

const { useState } = React;

function AddPersonForm(props) {
  const [person, setPerson] = useState("");

  function handleChange(e) {
    setPerson(e.target.value);
  }

  function handleSubmit(e) {
    props.handleSubmit(person);
    setPerson("");
    e.preventDefault();
  }
  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        placeholder="Add new contact"
        onChange={handleChange}
        value={person}
      />
      <button type="submit">Add</button>
    </form>
  );
}

function PeopleList(props) {
  const [person_, setPerson_] = useState("");
  function handleCLick(e) {
    setPerson_(e.target.textContent);
    props.handleCLick(person_);
  }

  return (
    <ul onClick={handleCLick}>
      {props.data.map((val, index) => (
        <li key={index}>{val}</li>
      ))}
    </ul>
  );
}

function ContactManager(props) {
  const [contacts, setContacts] = useState(props.data);

  function addPerson(name) {
    setContacts([...contacts, name]);
  }
  function removePerson(name_) {
    let filtered = contacts.filter(function (value) {
      return value != name_;
    });
    setContacts(filtered);
  }
  return (
    <div>
      <AddPersonForm handleSubmit={addPerson} />
      <PeopleList data={contacts} handleCLick={removePerson} />
    </div>
  );
}
const contacts = ["James Smith", "Thomas Anderson", "Bruce Wayne"];

ReactDOM.render(
  <ContactManager data={contacts} />,
  document.getElementById("root")
);

问题

在无序列表元素上设置 onClick 处理程序对我来说似乎有点奇怪,但您的问题是对 React 状态何时更新的误解。 React 状态更新被排队并 异步 处理。换句话说,当您将状态更新 setPerson_(e.target.textContent) in handleClick in PeopleList 排队时,person_ 尚未在下一行 props.handleCLick(person_); 中更新。您正在使用尚未更新的状态。

解决方案

只需将 click 事件对象的值直接发送到 props.handleClick 回调即可。您还可以删除本地 person_ 状态。

function PeopleList(props) {
  function handleCLick(e) {
    props.handleCLick(e.target.textContent);
  }

  return (
    <ul onClick={handleCLick}>
      {props.data.map((val, index) => (
        <li key={index}>{val}</li>
      ))}
    </ul>
  );
}