英文:
React: invalid hook call onSubmit function
问题
我正在使用 react-hook-form
和一个小的状态机来存储表单的值。
我将其用于一个包含两个选项的调查,用户点击一个答案,然后点击 "下一步" 按钮(提交类型)来进入下一个问题,依此类推。
问题是,当我想在提交函数中使用小状态机时,我遇到了一个错误:
无效的钩子调用。钩子只能在函数组件的主体内部调用...
我不知道我做错了什么。
onSubmit
代码:
export const onSubmit = (data) => {
const { actions, state } = useStateMachine({ updateAction });
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,
});
};
我的表单:
interface IFormProfileProps {
data: IHomeProps;
sizeQuestionnaire: number;
}
export const FormProfile = ({ data, sizeQuestionnaire }: IFormProfileProps) => {
const form = useForm({ shouldUnregister: true });
const { state } = useStateMachine();
const [valueChoice, setValueChoice] = useState(state[data?.questionCode]);
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>
);
};
希望这能帮到您。
英文:
I'm using react-hook-form
and little state machine to store the values of the form.
I use it for a survey with 2 choices, the user click on an answer, then click on the "next" button (submit type) to go on the next question, on so on.
The issue is when I want to use little state machine on the submit function I get an error:
> invalid hook call. Hooks can only be called inside of the body of a function component...
I don't know what i'm doing wrong.
onSubmit
code:
export const onSubmit = (data) => {
const { actions, state } = useStateMachine({ updateAction });
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,
});
};
My form :
interface IFormProfileProps {
data: IHomeProps;
sizeQuestionnaire: number;
}
export const FormProfile = ({ data, sizeQuestionnaire }: IFormProfileProps) => {
const form = useForm({ shouldUnregister: true });
const { state } = useStateMachine();
const [valueChoice, setValueChoice] = useState(state[data?.questionCode]);
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>
);
};
Any help would be appreciated.
答案1
得分: 1
SOLUTION 1
在 onSubmit
函数内部使用了 useStateMachine
,这就是为什么它告诉你在组件外部使用它。
SOLUTION 2
如果你想要使这段代码可重用,你可以创建一个 hook,例如 useOnSubmit
,然后在 FormProfile
组件内部使用该 hook:
然后,可以像这样使用它:
export const FormProfile = ({ data, sizeQuestionnaire }: IFormProfileProps) => {
const form = useForm({ shouldUnregister: true });
const { state } = useStateMachine();
const [valueChoice, setValueChoice] = useState(state[data?.questionCode]);
/* ------------- PART IN QUESTIONS */
const onSubmit = useOnSubmit();
return (
<form onSubmit={form.handleSubmit(onSubmit)}>
...
</form>
);
};
英文:
You are using: useStateMachine
inside the onSubmit
function. That is why it is telling you that you are using it outside of a component.
SOLUTION 1
Use it inside the component where you are using the onSubmit
. And also you should define that onSubmit
there:
export const FormProfile = ({ data, sizeQuestionnaire }: IFormProfileProps) => {
const form = useForm({ shouldUnregister: true });
const { state } = useStateMachine();
const [valueChoice, setValueChoice] = useState(state[data?.questionCode]);
/* ------------- PART IN QUESTIONS */
const { actions, state } = useStateMachine({ updateAction });
const onSubmit = (data) => {
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,
});
};
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>
);
};
SOLUTION 2
If you want to make that code reusable, you can create a hook, ex useOnSubmit
, and than use that hook inside the FormProfile
component:
export function useOnSubmit() {
const { actions, state } = useStateMachine({ updateAction });
const onSubmit = (data) => {
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,
});
};
return onSubmit;
}
Then, use it as such:
export const FormProfile = ({ data, sizeQuestionnaire }: IFormProfileProps) => {
const form = useForm({ shouldUnregister: true });
const { state } = useStateMachine();
const [valueChoice, setValueChoice] = useState(state[data?.questionCode]);
/* ------------- PART IN QUESTIONS */
const onSubmit = useOnSubmit();
return (
<form onSubmit={form.handleSubmit(onSubmit)}>
...
</form>
);
};
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论