react router 的 form 组件默认使用 get 方法提交,而 get 提交不会调用路由定义的 action;必须显式设置 `method="post"`(或 put/patch/delete)才能触发 action 函数。
在 React Router v6.4+ 的数据路由(Data Router)模式中,<form></form> 是一个关键的数据提交组件,但它不会自动触发 action 函数——除非你明确指定非 get 的 HTTP 方法。这是开发者最容易忽略的核心机制:只有 post、put、patch 或 delete 方法的表单提交才会调用对应路由的 action,而 get(默认值)仅执行导航并拼接查询参数,等效于点击链接。
你需要在 <form></form> 上添加 method="post",并确保提交按钮具有 type="submit"(虽为 HTML 默认值,但显式声明可避免意外行为,例如按钮被误设为 type="button"):
|
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 React from 'react'; import { Form } from 'react-router-dom';
export async function action({ request }: { request: Request }) { console.log('? Action triggered!'); const formData = await request.formData(); const email = formData.get('email') as string; const password = formData.get('password') as string;
// 示例:模拟登录验证(实际应调用 API) if (email && password) { return { success: true, message: 'Login successful' }; }
throw new Response('Invalid credentials', { status: 400 }); }
const AdminLogin = () => { return ( <div> <Form method="post"> {/* ← 关键:必须是非-get 方法 */} <input type="text" name="email" placeholder="Enter email or User ID" autoComplete="username" /> <input type="password" name="password" placeholder="Enter Password" autoComplete="current-password" /> <button type="submit">Log In</button> {/* ← 显式声明 type */} </Form> </div> ); };
export default AdminLogin; |
你当前的 createBrowserRouter 配置完全合规:
|
<Route path="adminlogin" action={action} element={<AdminLogin />} /> |
只要组件内 <form method="post"></form> 就绪,action 即可被调用。无需额外包裹 loader、errorElement 或调整嵌套路由结构。
总结:GET 是导航,POST/PUT/PATCH/DELETE 才是数据操作。牢记这一设计哲学,就能避开 90% 的 action 不触发问题。