发布于 2026-01-06 0 阅读
0

如何在 React 中处理表单?另一种方法。额外内容:创建自定义辅助方法。

如何在 React 中处理表单:另一种方法

额外奖励:创建你自己的辅助方法

我刚开始接触 React 的时候,需要重新学习如何管理表单。使用`<form> Controlled` 或 `<form>`代替`<form>` ,绑定事件处理程序,并在 `<form>` 中管理状态,或者最近尝试使用 `<form>`或 ` <form>` 来管理状态uncontrolleddefaultValuevalueonChangereduxuseStateuseReducer

如果我告诉你这件事其实可以更简单呢?别犯我五年前犯过的那些新手错误。使用 React 并不意味着 React 需要控制一切!要掌握 HTML 和 JavaScript 的基础知识。

我们以提交和验证多字段表单为例w3schools。我把类组件转换成了函数式组件,因为我发现这样更容易阅读。

function MyForm() {
  const [state, setState] = useState({ username: '', age: null });

  const handleSubmit = (event) => {
    event.preventDefault();

    const age = state.age;

    if (!Number(age)) {
      alert('Your age must be a number');
      return;
    }

    console.log('submitting', state);
  };

  const handleChange = (event) => {
    const name = event.target.name;
    const value = event.target.value;
    setState({ ...state, [name]: value });
  };

  return (
    <form onSubmit={handleSubmit}>
      <h1>Hi!</h1>

      <p>Enter your name:</p>
      <input type="text" name="username" onChange={handleChange} />

      <p>Enter your age:</p>
      <input type="text" name="age" onChange={handleChange} />

      <br /><br />
      <input type="submit" />
    </form>
  );
}
Enter fullscreen mode Exit fullscreen mode

这段代码量很大,但用来处理表单却很麻烦。你现在看到的是,每次输入框被按下(内容发生变化)时,表单状态都会更新。提交表单时,系统会读取这个状态,进行验证,然后将其输出到控制台。

现在,让我们通过移除所有状态管理和变更处理程序来简化它。

function MyForm() {
  return (  
    <form>
      <h1>Hi!</h1>

      <p>Enter your name:</p>
      <input type="text" name="username" />

      <p>Enter your age:</p>
      <input type="text" name="age" />

      <br /><br />
      <input type="submit" />
    </form>
  );
}
Enter fullscreen mode Exit fullscreen mode

这是渲染表单需要返回的 HTML(JSX)代码。请注意,这段代码除了渲染 HTML 之外不做任何其他操作,它不会进行验证,也不会处理表单提交。我们稍后会添加这些功能。

但首先,先别管 React,想想不用框架该怎么实现这个功能。我们该如何使用 JavaScript 读取这个表单的值呢?当我们拥有一个表单引用时(例如使用 `<form>`)document.getElementById('form'),就可以使用 ` FormDatagetValues()` 来读取表单值。

const element = document.getElementByID('form')
const data = new FormData(element);
Enter fullscreen mode Exit fullscreen mode

现在,data如果类型为FormData,当你需要一个可以序列化的对象时,需要先将其转换为普通对象。我们通常Object.fromEntries这样做。

Object.fromEntries(data.entries());
Enter fullscreen mode Exit fullscreen mode

接下来,我们将把这些元素重新组合起来,并创建一个onSubmit处理程序。请记住,表单提交后,表单元素可以通过该event.currentTarget属性访问。

const handleSubmit = (event) => {
  event.preventDefault();

  const data = new FormData(event.currentTarget);
  const values = Object.fromEntries(data.entries());
  console.log(values); // { name: '', age: '' }
};
Enter fullscreen mode Exit fullscreen mode

这仍然是纯 JavaScript 代码,没有使用任何框架或库。验证功能可以根据需要添加到最合适的位置。可以直接使用表单数据,也可以使用普通对象。

// get values using FormData
const age = data.get('age');

// get values using plain object
const age = values.age;
Enter fullscreen mode Exit fullscreen mode

当我们把所有这些部分组合在一起时,我们就得到了最终可用的 React 表单:

function MyForm() {
  const handleSubmit = (event) => {
    event.preventDefault();

    const data = new FormData(event.currentTarget);
    const values = Object.fromEntries(data.entries());

    if (!Number(values.age)) {
      alert('Your age must be a number');
      return;
    }

    console.log('submitting', values);
  };

  return (
    <form onSubmit={handleSubmit}>
      <h1>Hi!</h1>

      <p>Enter your name:</p>
      <input type="text" name="username" />

      <p>Enter your age:</p>
      <input type="text" name="age" />

      <br /><br />
      <input type="submit" />
    </form>
  );
}
Enter fullscreen mode Exit fullscreen mode

这样看起来怎么样?不再需要状态管理,不再需要变更处理程序,只需处理表单提交事件,并使用纯 HTML/JavaScript 方法即可。无需 React 特有的功能,也无需使用任何库,所有方法都基于原生方法。

额外奖励:创建你自己的辅助方法

当您需要处理大量表单时,您可能需要将其中一部分提取到一个辅助函数中,从而减少代码中重复行的数量。

将值提取部分提取到一个单独的函数中非常简单:

function getFormValues(event) {
  const data = new FormData(event.currentTarget);
  return Object.fromEntries(data.entries());
}

export default function MyForm() {
  const handleSubmit = (event) => {   
    event.preventDefault();
    const values = getFormValues(event);

    console.log('submitting', values); // { name: '', age: '' }
  };

  // ...
Enter fullscreen mode Exit fullscreen mode

但这仍然导致需要重复执行这些操作preventDefaultgetFormValues调用。现在每个处理程序都需要以以下内容开头:

event.preventDefault();
const values = getFormValues(event);
Enter fullscreen mode Exit fullscreen mode

这个问题我们也可以通过创建一个回调式包装器来解决。你知道吗?不如给它起个酷炫的、类似钩子函数的名字。这个函数其实没什么特别的,它跟钩子函数一点关系都没有,但它看起来很棒!我们都喜欢酷炫的东西,对吧?

function useSubmit(fn) {
  return (event) => {
    event.preventDefault();

    const values = getFormValues(event);
    return fn(values);
  };
}
Enter fullscreen mode Exit fullscreen mode

有了这个“钩子”,处理表单就变得非常简单:

export default function MyForm() {
  const handleSubmit = useSubmit((values) => {        
    console.log('submitting', values);
  });

  return (
    <form onSubmit={handleSubmit}>
      <h1>Hi!</h1>

      <p>Enter your name:</p>
      <input type="text" name="username" />

      <p>Enter your age:</p>
      <input type="text" name="age" />

      <br /><br />
      <input type="submit" />
    </form>
  );
}
Enter fullscreen mode Exit fullscreen mode

您可以随意在非 React 代码中使用该函数。它与框架无关,并且适用于纯 HTML 和 JavaScript。

说实话,我不会useSubmit在生产代码中这样调用它。相反,我会使用更通用的写法,比如 `@Hook` onSubmithandleSubmit`@Hook` 甚至 `@Hook` submit。它不是一个 Hook,把它伪装成 Hook 可能会造成混淆。


👋 我是 Stephan,我正在开发updrafts.app。如果你想了解更多我的非主流观点,请在Twitter上关注我。

文章来源:https://dev.to/smeijer/simple-form-handling-in-react-o72