如何在不阻塞提交处理程序的情况下对提交使用浏览器验证

How to use browser validation on submit without blocking the submit handler

HTML5 允许我们从表单外的按钮提交表单。

<form id="myform">
  <input required/>
</form>
<button type="submit" form="myform"/>

正如您在以下代码片段中所见,这显然不适用于 React。

const App = () => {
  const [value, setValue] = React.useState("");
  const [result, setResult] = React.useState("");

  const onSubmit = (e) => {
    e.preventDefault();
    if (!value) {
      setResult("Error");
    } else {
      setResult(value);
    }
  };

  return (
    <div className="box">
      <form id="myform" className="box" onSubmit={onSubmit}>
        <h3>My form</h3>
        <input
          className="input"
          value={value}
          required
          onChange={(e) => setValue(e.target.value)}
        />
      </form>
      <button type="submit" form="myform" className="button">
        Submit
      </button>
      <div>Result: {result}</div>
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById("root"));
body {
  height: 100vh;
  margin: 0;
  display: grid;
  place-items: center;
}

.box {
  background-color: #fff;
  border-radius: 6px;
  box-shadow: 0 2px 3px rgb(10 10 10 / 10%), 0 0 0 1px rgb(10 10 10 / 10%);
  color: #4a4a4a;
  display: block;
  padding: 1.25rem;
  margin-bottom: 1.5rem;
}

.button {
  border: 1px solid transparent;
  border-radius: 4px;
  font-size: 1rem;
  height: 2.25em;
  line-height: 1.5;
  background-color: #fff;
  border-color: #dbdbdb;
  border-width: 1px;
  color: #363636;
  cursor: pointer;
  justify-content: center;
  text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>

我希望“结果”框显示“错误”。相反,浏览器验证启动并且根本不调用表单提交处理程序。

我是不是做错了什么?

编辑

感谢对此 post 的评论,我意识到我的问题基于一个错误的假设:将提交按钮放在(无效的)表单之外会导致浏览器阻止提交的执行处理程序。相反,这只是具有验证和提交处理程序的任何表单的正常行为。

所以,如果我们想挽救这个问题,这就是我想在表单提交上实现的:

我通过在按钮上使用简单的单击处理程序而不是在表单上使用提交处理程序来解决这个问题。但如果仍然使用提交按钮和处理程序并仅禁用浏览器行为以防止提交处理程序执行并显示气球消息会更好。

您已将字段标记为必填。你需要删除它。

<input className="input" value={value} onChange={(e) => setValue(e.target.value)} />

const App = () => {
  const [value, setValue] = React.useState("");
  const [result, setResult] = React.useState("");

  const onSubmit = (e) => {
    e.preventDefault();
    if (!value) {
      setResult("Error");
    } else {
      setResult(value);
    }
  };

  return (
    <div className="box">
      <form id="myform" className="box" onSubmit={onSubmit}>
        <h3>My form</h3>
        <input
          className="input"
          value={value}
          onChange={(e) => setValue(e.target.value)}
        />
      </form>
      <button type="submit" form="myform" className="button">
        Submit
      </button>
      <div>Result: {result}</div>
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById("root"));
body {
  height: 100vh;
  margin: 0;
  display: grid;
  place-items: center;
}

.box {
  background-color: #fff;
  border-radius: 6px;
  box-shadow: 0 2px 3px rgb(10 10 10 / 10%), 0 0 0 1px rgb(10 10 10 / 10%);
  color: #4a4a4a;
  display: block;
  padding: 1.25rem;
  margin-bottom: 1.5rem;
}

.button {
  border: 1px solid transparent;
  border-radius: 4px;
  font-size: 1rem;
  height: 2.25em;
  line-height: 1.5;
  background-color: #fff;
  border-color: #dbdbdb;
  border-width: 1px;
  color: #363636;
  cursor: pointer;
  justify-content: center;
  text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>

我发现 invalid event 的存在。当尝试使用无效数据提交表单时引发。可以阻止此事件的默认值以避免浏览器显示默认警告气球。显示验证错误的逻辑可以在无效事件处理程序中实现,让提交处理程序只关心提交验证数据。

<form onInvalid={e => {
  e.preventDefault()
  // show validation errors
} onSubmit={e => {
  e.preventDefault()
  // Submit data
}>
  <input required/>
  <button type="submit"/>
</form>