react router 在 v6 版本提供了一个基于 form表单元素 的增强组件 Form,可以与 react router 的数据操作配合使用

简单了解 form 表单

<form> 是 HTML 中收集用户输入数据并提交到服务器的容器标签,主要使用两个核心属性

  • action:表单数据提交的 URL,默认提交到当前的 URL
  • method:提交数据使用的 HTTP 方法,默认为 get

form 标签中通常使用 <input><button> 作为输入标签,简单示例如下

1
2
3
4
<form action="/submit" method="post">
<input type="text" name="username" placeholder="请输入用户名" />
<button type="submit">提交</button>
</form>

对于以上示例,浏览器对 form 表单的默认提交流程如下

  1. 浏览器收集 form 表单中带有 name 属性的输入标签,将 name 和输入值组成键值对
  2. 对数据进行编码,默认编码为 application/x-www-form-urlencoded
  3. /submit 地址发送一个 post 请求
  4. 页面刷新或跳转

action 属性

在 HTML 的 form 标签中,action 属性要求指定一个绝对路径,Form 组件默认使用的是当前路由的路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function ProjectsLayout() {
return (
<>
<Form method="post" />
<Outlet />
</>
);
}

function ProjectsPage() {
return <Form method="post" />;
}

const router = createBrowserRouter([
{
path: "/projects",
element: <ProjectsLayout/>,
children: [
{path: ":projectId", element: <ProjectsPage/>}
]
}
])

以上示例中,<ProjectsLayout> 的 URL 为 /projects,因此 <Form> 中的 action 默认为 /projects

method 属性

method 属性默认为 get,此时 Form 组件与 HTML 的 form 标签行为一致,提交时会将表单数据编码为查询参数,添加到 URL 中并进行导航

1
2
3
4
<Form method="get" action="/products">
<input type="text" name="q"/>
<button type="submit">Search</button>
</Form>

若用户输入 food,则查询参数为 q=food,点击按钮提交后会导航到 /products?q=food

对于其他 method 值,如 postdelete 等,react router 会将 action 地址与路由的路径匹配,调用该路由的 action 回调,实现数据写入与导航逻辑

对于 postdelete 之类的方法,导航逻辑需要在路由的 action 回调中手动实现,因此 react router 中的 Form 默认不会进行导航

导航

Form 组件在提交后可能进行导航,可以使用 navigate={false} 来禁止导航

Form 导航也支持 replacerelativestate 等参数

useSubmit

useSubmit 函数用于程序式地实现 Form 表单提交,简单示例如下

1
2
3
4
import { useSubmit } from 'react-router';

const submit = useSubmit()
submit(target, options)

submit 函数接收两个参数

  • target:提交数据,SubmitTarget 类型
  • options:表单属性及导航选项

target 参数

target 参数为 SubmitTarget 类型,可以传入提交元素的 DOM、FormData、URL 查询参数以及 JSON 数据,定义如下

1
type SubmitTarget = HTMLFormElement | HTMLButtonElement | HTMLInputElement | FormData | URLSearchParams | JsonValue | null;

示例如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import { useSubmit } from 'react-router';

function MyForm() {
const submit = useSubmit();

// 提交一个 input 元素
const handleInputChange = (event) => {
submit(event.currentTarget); // 提交表单输入元素
};

// 提交 FormData(比如文件上传或传统表单)
const handleFormDataSubmit = () => {
const formData = new FormData();
formData.append("cheese", "gouda");
submit(formData); // 默认会以 FormData 方式提交,通常用于 POST
};

// 提交 JSON 对象(使用 application/json 编码)
const handleJsonSubmit = () => {
submit(
{ key: "value" },
{ method: "post", encType: "application/json" }
);
};

// 直接提交 URLSearchParams 字符串形式
const handleSearchParamsSubmit = () => {
// 直接传入查询字符串或构造URLSearchParams对象
submit("cheese=gouda&toasted=yes");
};

return (
<div>
<input type="text" onChange={handleInputChange}/>
<button onClick={handleFormDataSubmit}>Submit FormData</button>
<button onClick={handleJsonSubmit}>Submit JSON</button>
<button onClick={handleSearchParamsSubmit}>Submit Query String</button>
</div>
);
}

options 参数

options 参数接收一个对象,其中的可设置项与 Form 组件属性基本相同

  • action
  • method
  • navigate
  • relative
  • replace
  • state