React中onSubmit调用useStateMachine触发无效Hook调用错误求助
问题解决:Invalid Hook Call 错误排查
错误原因
你遇到的invalid hook call错误,核心原因是违反了React Hook的调用规则:useStateMachine是React Hook,只能在函数组件的顶层作用域或自定义Hook中调用,绝对不能在事件处理函数(比如onSubmit)内部调用。
你的原有onSubmit函数中直接调用了useStateMachine,完全不符合Hook的使用规范,所以触发了错误。
解决方案
把useStateMachine的调用移到组件的顶层,获取state和actions后,再在onSubmit中使用它们。下面提供两种可行的修改方式:
方式1:在组件内部定义onSubmit
直接将onSubmit函数写在FormProfile组件内部,这样就能直接访问顶层的state和actions:
interface IFormProfileProps { data: IHomeProps; sizeQuestionnaire: number; } export const FormProfile = ({ data, sizeQuestionnaire }: IFormProfileProps) => { const form = useForm({ shouldUnregister: true }); // 组件顶层调用useStateMachine,获取state和actions const { state, actions } = useStateMachine(); const [valueChoice, setValueChoice] = useState(state[data?.questionCode]); // 组件内部定义onSubmit,直接使用state和actions const onSubmit = (formData) => { actions.updateAction({ ...formData, step: state.surveyInfos.step + 1, tags: [...state.surveyInfos.tags, formData.tags], Q1Score: state.surveyInfos.Q1Score + formData.quotationResponse, Q2Score: state.surveyInfos.Q2Score + formData.quotationResponse, }); }; return ( <form onSubmit={form.handleSubmit(onSubmit)}> <FormControl component="fieldset"> <FormLabel component="legend"> <Typography variant="h4"> {data.data[0]?.questionText} </Typography> </FormLabel> <Box display="flex" flex={1} gap={5}> {data?.data?.map((value, index) => { return ( <Box key={index} display="flex" flex={1}> <input {...form.register(data?.questionCode, { required: true })} type="radio" checked={valueChoice === `response-card-${value?.questionCode}-${index}`} value={`${value.subSurvey}-${value.tag}-${index}`} onChange={() => setValueChoice(`response-card-${value?.questionCode}-${index}`)} id={`field-${data?.questionCode}-${index}`} /> <label htmlFor={`field-${data?.questionCode}-${index}`} key={index} > <ResponseCard borderColor={ valueChoice === `response-card-${value?.questionCode}-${index}` ? grey.light : state[data?.questionCode] === `response-card-${value?.questionCode}-${index}` ? grey.light : grey.extraLight } responseTitle={value?.answerTitle} responseText={value?.answerText} /> </label> </Box> ); })} </Box> </FormControl> <ActionButtons sizeQuestionnaire={sizeQuestionnaire} /> </form> ); };
方式2:将state和actions作为参数传给外部onSubmit
如果需要保持onSubmit是独立的外部函数,可以在组件调用时把state和actions作为参数传递进去:
首先修改外部的onSubmit函数:
export const onSubmit = (data, state, actions) => { actions.updateAction({ ...data, step: state.surveyInfos.step + 1, tags: [...state.surveyInfos.tags, data.tags], Q1Score: state.surveyInfos.Q1Score + data.quotationResponse, Q2Score: state.surveyInfos.Q2Score + data.quotationResponse, }); };
然后修改FormProfile组件中的表单提交逻辑:
export const FormProfile = ({ data, sizeQuestionnaire }: IFormProfileProps) => { const form = useForm({ shouldUnregister: true }); const { state, actions } = useStateMachine(); const [valueChoice, setValueChoice] = useState(state[data?.questionCode]); return ( // 调用handleSubmit时,把state和actions传给onSubmit <form onSubmit={form.handleSubmit((data) => onSubmit(data, state, actions))}> {/* 原有表单内容保持不变 */} </form> ); };
关键注意事项
- 所有React Hook(包括
useState、useForm、useStateMachine等)必须在函数组件的顶层作用域调用,不能在嵌套函数、事件处理、循环、条件判断中使用。 - React依赖Hook的调用顺序来管理组件状态,违反顺序会导致状态混乱或报错。
内容的提问来源于stack exchange,提问作者Florie Anstett
相关产品推荐
相关产品推荐

