React useFormStatus钩子在Next.js项目中未按预期工作求助
React + Next.js中useFormStatus()钩子不生效的问题解决
问题场景与代码
在React + Next.js项目中使用useFormStatus()钩子时,服务器动作可正常执行,但钩子始终无法识别表单pending状态,导致按钮不会禁用、文本也不切换。原代码如下:
import { useFormStatus } from "react-dom"; type SurveyResultProps = { answers: Record<string, Answer> } const SurveyResult: React.FC<SurveyResultProps> = ({ answers }: SurveyResultProps) => { const [resultText, setResultText] = useState(''); const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => { event.preventDefault(); const text = await getResultText(answers); setResultText(text); }; function Submit() { const asdf = useFormStatus(); console.log(asdf); const { pending } = asdf; return <Button type="submit" disabled={pending} text={pending ? "Submitting..." : "Submit"} /> } return <div> <form onSubmit={handleSubmit}> <Submit /> </form> {resultText && ( <pre>{resultText}</pre> )} </div>; }
存在的问题
useFormStatus始终返回pending: false- 提交按钮从未被禁用
- 按钮文本始终显示为
Submit,不会切换为Submitting...
控制台输出示例:
{pending: false, data: null, method: null, action: null} {pending: false, data: null, method: null, action: null}
问题原因与解决方法
1. 核心用法错误:自定义onSubmit无法触发钩子状态
useFormStatus是为React内置的表单提交流程设计的,它依赖表单的action属性绑定的提交动作(尤其是服务器动作)来感知状态。如果用onSubmit+event.preventDefault()自定义提交逻辑,会绕过React的内置处理,导致钩子无法捕获pending状态。
2. 正确实现方式
步骤1:将提交逻辑改为服务器动作(Next.js App Router)
将getResultText标记为服务器动作(放在单独文件或组件顶部添加'use server'):
'use server'; export async function getResultText(answers: Record<string, Answer>) { // 原服务器逻辑代码 }
步骤2:修改表单与组件逻辑
移除自定义onSubmit,改用表单的action属性绑定服务器动作,确保Submit组件是表单的直接子组件(或表单上下文内的后代组件):
import { useFormStatus } from "react-dom"; import { getResultText } from './actions'; type SurveyResultProps = { answers: Record<string, Answer> } const SurveyResult: React.FC<SurveyResultProps> = ({ answers }) => { const [resultText, setResultText] = useState(''); // 绑定到表单action的处理函数 async function handleFormAction() { const text = await getResultText(answers); setResultText(text); } function Submit() { const { pending } = useFormStatus(); return <Button type="submit" disabled={pending} text={pending ? "Submitting..." : "Submit"} /> } return <div> {/* 使用action属性绑定处理函数,而非onSubmit */} <form action={handleFormAction}> <Submit /> </form> {resultText && <pre>{resultText}</pre>} </div>; }
3. 版本与特性确认
- 确保
react和react-dom版本≥18.2.0(useFormStatus已从canary转为稳定API) - Next.js版本≥13.4+(支持App Router与服务器动作)
内容的提问来源于stack exchange,提问作者Aaron Brager
相关产品推荐
相关产品推荐

