首页 > 解决方案 > 如果不单击多次,React 提交表单按钮将不起作用

问题描述

我正在开发我的第一个 React 程序,它是由 Sololearn(Contact Manager)提供的。我正在尝试添加一个功能来搜索联系人:SearchName。但是,我需要多次单击“搜索”按钮才能使其正常工作。有人可以告诉我哪里出错了吗?例如,首先在输入要搜索的名称字段中输入James Smith会给出“不在列表中”。然后再次单击时,它会更新为is in list

这是代码:

import React, { useState } from "react";
import ReactDOM from "react-dom";

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

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

  function handleSubmit(e) {
    if (person !== "") {
      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 RemovePersonForm(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="enter name to delete"
        onChange={handleChange}
      />
      <button type="submit">Delete</button>
    </form>
  );
}

function PeopleList(props) {
  const arr = props.data;
  const listItems = arr.map((val, index) => <li key={index}>{val}</li>);
  return <ul>{listItems}</ul>;
}
function SearchName(props) {
  const [contacts, setContacts] = useState(props.data);
  const [person, setPerson] = useState("");
  const [isInList, setIsInList] = useState(false);
  const [text, setText] = useState("");
  function handleChange(e) {
    setPerson(e.target.value);
  }
  function handleSubmit(e) {
    setIsInList(false);
    for (var c of contacts) {
      if (c == person) {
        setIsInList(true);
        break;
      }
    }
    if (isInList) {
      setText("is in list");
    } else {
      setText("is not in list");
    }

    e.preventDefault();
  }
  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        placeholder="enter name to search"
        onChange={handleChange}
      />
      <button type="sumbit">Search</button>
      <p>{text}</p>
    </form>
  );
}
function ContactManager(props) {
  const [contacts, setContacts] = useState(props.data);

  function addPerson(name) {
    setContacts([...contacts, name]);
  }
  function removePerson(name) {
    var newContacts = new Array();
    var i = 0;
    for (var c of contacts) {
      if (c != name) {
        newContacts[i] = c;
        i++;
      }
    }
    setContacts(newContacts);
  }
  return (
    <div>
      <AddPersonForm handleSubmit={addPerson} />
      <RemovePersonForm handleSubmit={removePerson} />
      <SearchName data={contacts} />
      <PeopleList data={contacts} />
    </div>
  );
}
const contacts = ["James Smith", "Thomas Anderson", "Bruce Wayne"];

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

标签: javascriptreactjsjsx

解决方案


根本问题是,由于setState是异步的,isInList所以在您签入时还没有时间更改handleSubmit

但是,由于 printtext严格来说是是否isInList为真的函数,因此它不应该是一个单独的状态原子。如果计算更复杂,我建议使用useMemo它。

在类似的说明中,您不应该将data道具“分叉”到本地联系人状态。

最后,您可以将查找过程简化为简单的.find调用而不是循环。

function SearchName(props) {
  const [person, setPerson] = useState("");
  const [isInList, setIsInList] = useState(false);
  function handleChange(e) {
    setPerson(e.target.value);
  }
  function handleSubmit(e) {
    setIsInList(props.data.find((c) => c === person));
    e.preventDefault();
  }
  const text = isInList ? "is in list" : "is not in list";
  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        placeholder="enter name to search"
        onChange={handleChange}
      />
      <button type="sumbit">Search</button>
      <p>{text}</p>
    </form>
  );
}

推荐阅读