Form

Form组件是对 HTML 中form标签的一个封装,它的功能只是模拟了 HTML 中表单的各种操作,直接使用Form组件进行表单的提交一样会引起页面的导航。需要注意的是这个Form组件并不支持表单验证等表单支持库中提供的功能。

Tip

如果不想引起页面的导航操作,需要使用useFetcher() Hook。

跟 HTML 中的form标签一样,Form组件中常用的属性也是methodaction,其中method依旧是用来定义表单的提交方法,而action也是用来定义表单的提交路径的。如果Form组件在使用的时候没有定义action属性,那么Form组件将默认提交到当前组件的action方法或者是在组件树中拥有action方法的距离当前组件最近的父级组件。

表单在提交并完成action方法的调用后,会调用loader方法来刷新页面上的数据。

get方法

如果将Form组件的method属性定义为get,即采用GET方法提交表单,那么整个表单将产生一个导航到action属性的查询,所有的表单内容将形成一套查询串(SearchParams)。例如以下这个搜索表单的例子。

function SearchForm() {
  return (
    <Form method="get" action="/products">
      <input type="text" name="k" placeholder="请输入检索关键字" />
      <button type="submit">查询</button>
    </Form>
  );
}

在这个示例中提交表单将导航到/prodcuts?k=...的 URL 上。提交methodget的表单会调用路由中定义的loader方法。

replace

replace属性主要是用来清除和重置浏览历史堆栈的,但是根据Form组件上其他属性的不同取值,会有不同的默认行为。根据 React Router 文档中的列举,这些默认行为大致有以下这些。

  • method取值为get时,replacefalse
  • 根据action属性的不同,replace存在不同的默认取值。
    • action方法抛出异常,replacefalse
    • action导航至当前页面,replacetrue
    • action导航到其他位置,replacefalse
    • 其他情况下,replace都为false

reloadDocument

Form组件设置reloadDocument属性,将会使Form组件跳过 React Router 的表单提交操作,直接使用浏览器中的原生表单提交操作,并使页面产生刷新。

preventScrollReset

这个属性是需要搭配<ScrollRestoration>组件使用的,<ScrollRestoration>组件可以在表单提交并导航到新页面时重置页面的滚动条到之前的位置。但是如果设置Form组件上的preventScrollReset属性为true,将会阻止页面重置滚动条的动作。

useSubmit

useSubmit() Hook 可以返回一个方法用于提供开发者采用代码方式提交表单。其返回的函数接受两种参数,第一种是任意的表单或者表单控件的ref,第二种是一个FormData类型的表单数据以及配置表单提交目标和方法的配置项。

其使用方法十分简单,如以下示例所示。

/* 示例一:用在Form组件上 */
function SearchForm() {
  const submit = useSubmit();

  return (
    <Form onChange={(event) => submit(event.currentTarget)}>
      {/* 实际表单内容 */}
    </Form>
  );
}

/* 示例二:用在提交按钮上 */
function SearchForm() {
  const ref = useRef(null);
  const submit = useSubmit();

  const handleAction = useCallback(() => {
    submit(ref.current);
  }, [submit, ref]);

  return (
    <Form>
      <button type="submit" ref={ref}>
        提交
      </button>
      {/* 其他代码 */}
    </Form>
  );
}

/* 示例三:直接提交表单内容 */
const formData = new FormData();
formData.append("field", someVlaue);
submit(formData);