React Router单表单实现双提交动作的问题求助
解决React Router单表单多提交动作的问题
你遇到的错误核心是:点击Clear按钮时,请求被发送到了/foo/:uid路由(该路由未配置action),而非预期的/foo/:uid/clear,导致405 Method Not Allowed错误。以下是两种无需拆分表单的解决方案:
方法一:修正formAction为绝对路径
React Router的<Form>组件对相对路径的formAction解析可能出现偏差,直接使用绝对路径可以确保请求发送到正确的路由:
import { useParams } from 'react-router-dom'; export default function Foo() { const navigation = useNavigation(); const { uid } = useParams(); // 获取当前路由的uid参数 function handleOnClickClear(event) { if (!confirm("Please confirm you want to clear embeddings")) { event.preventDefault(); } } return ( <> <Form action={`/foo/${uid}/update`} method="post" id="foo-form"> <input id="label" name="label" placeholder="Label" /> <textarea id="text" name="text" placeholder="Text" rows="5" cols="80" wrap="soft" required ></textarea> <button type="submit">Submit</button> <button type="submit" form="foo-form" formAction={`/foo/${uid}/clear`} onClick={handleOnClickClear} > Clear </button> </Form> </> ); }
这种方式保持了路由的拆分结构,适合update和clear逻辑差异较大的场景。
方法二:合并action逻辑到父路由
如果业务逻辑相对简单,可以将两个动作的逻辑合并到/foo/:uid路由的action中,通过按钮的name和value区分操作:
1. 修改Foo组件的按钮
给两个提交按钮添加name="action"和对应的value:
export default function Foo() { const navigation = useNavigation(); function handleOnClickClear(event) { if (!confirm("Please confirm you want to clear embeddings")) { event.preventDefault(); } } return ( <> <Form method="post" id="foo-form"> <input id="label" name="label" placeholder="Label" /> <textarea id="text" name="text" placeholder="Text" rows="5" cols="80" wrap="soft" required ></textarea> <button type="submit" name="action" value="update">Submit</button> <button type="submit" name="action" value="clear" onClick={handleOnClickClear} > Clear </button> </Form> </> ); }
2. 合并action逻辑并更新路由
创建合并后的action函数,然后给/foo/:uid路由添加该action:
// 合并update和clear的逻辑 export async function fooAction({ request, params }) { const formData = await request.formData(); const actionType = formData.get('action'); if (actionType === 'update') { // 原updateAction逻辑 console.log(request); return redirect(`/provider/${params.uid}`); } else if (actionType === 'clear') { // 原clearAction逻辑 console.log(`Clearing provider ${params.uid}`); return redirect(`/provider/${params.uid}`); } return redirect(`/provider/${params.uid}`); } // 更新路由配置 const router = createBrowserRouter( [ { path: "/", element: <Root />, errorElement: <ErrorPage />, loader: rootLoader, children: [ { errorElement: <ErrorPage />, children: [ { index: true, element: <Index /> }, { path: "foo/:uid", element: <Foo />, loader: fooLoader, action: fooAction, // 添加合并后的action }, // 移除原foo/:uid/update和foo/:uid/clear子路由 ], }, ], }, ], );
这种方式简化了路由结构,减少了路由维护成本。
内容的提问来源于stack exchange,提问作者milosgajdos
相关产品推荐
相关产品推荐

