我需要创建一个搜索表单,使用 React 将其结果发布到新选项卡/窗口。
目前,使用formik或react-hook-forms,我将利用原生表单属性来实现这一点。
<Form action="my/results/page" method="POST" target="_blank" ref={formEl}>
这允许我在用户提交表单并完成验证后将搜索结果加载到新选项卡中。
我想实现相同的功能,但使用 React 19 的 useActionState 钩子。
到目前为止,我的表单组件和提交工作已经完成,减去了新选项卡/窗口的要求。
function handleFormSubmission(previousState, formData) {
newFieldValues = Object.fromEntries(formData);
const fieldsAreValid = validateFields(newFieldValues , fieldConfig);
if (fieldsAreValid) {
// Need to post newFieldValues to "my/results/page" in a new tab here
console.log('submitted', newFieldValues);
}
return newFieldValues; // Update form state for react.
}
const [state, formAction, isSubmitting] = useActionState(handleFormSubmission, initialValues);
...
return (
<form action={formAction} ref={formEl}>
{children}
</form>
);
以前,如果验证失败,我只需调用 event.stopPropagation() 即可阻止提交。否则,表单将自动发布到新目标。
使用 useActionState 时,它会自动将方法设置为 POST,但它也会覆盖 form 操作属性,并在用户提交时自动调用 event.stopPropagation() 。这使我无法利用本机操作和目标属性来指定结果页面和窗口。
那么如何将表单数据提交到 useActionState 使用的 handleFormSubmission 函数中的新目标/选项卡?
在这上面花了太长时间,我终于找到了一个可行的解决方案。
HTMLFormElement:requestSubmit() 方法允许您指定一个覆盖父表单提交行为的提交按钮。
因此,要使此表单在新窗口中打开,您只需调用 requestSubmit 方法并引用指定您所需的最终提交行为的按钮。该按钮必须是提交类型,并且也是您正在提交的表单的子按钮。不过该按钮可以隐藏。
我遇到的一个问题是 requestSubmit 在表单的操作/提交处理程序中不起作用。我猜这是因为表单已经处于待处理/过渡状态?为了解决这个问题,我将提交请求放在 useEffect 中。
这是上面的示例,已更新以在新选项卡中打开结果。
const [loadReport, setLoadReport] = useState(false);
function handleFormSubmission(previousState, formData) {
newFieldValues = Object.fromEntries(formData);
const fieldsAreValid = validateFields(newFieldValues, fieldConfig);
if (fieldsAreValid) {
// Need to post newFieldValues to "my/results/page" in a new tab here
setLoadReport(true);
}
return newFieldValues; // Update form state for react.
}
const [state, formAction, isSubmitting] = useActionState(handleFormSubmission, initialValues);
useEffect(() => {
if (loadReport) {
// This button submission overrides the default form submission behavior.
formEl.current.requestSubmit(reportLoaderButton.current);
setLoadReport(false);
}
}, [loadReport, formEl, reportLoaderButton]);
...
return (
<form action={formAction} ref={formEl}>
{children}
<button
ref={reportLoaderButton}
type="submit"
formMethod="POST"
formAction={`my/results/page`}
formTarget="_blank"
style={{ display: 'none' }}
label="finalFormSubmission"
/>
</form>
);
请参阅文档了解更多详细信息。
requestSubmit:https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/requestSubmit
useActionState:https://react.dev/reference/react/useActionState