React: invalid hook call onSubmit function

huangapple go评论73阅读模式
英文:

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) =&gt; {
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) =&gt; {
const form = useForm({ shouldUnregister: true });
const { state } = useStateMachine();
const [valueChoice, setValueChoice] = useState(state[data?.questionCode]);
return (
&lt;form
onSubmit={form.handleSubmit(onSubmit)}
&gt;
&lt;FormControl component=&quot;fieldset&quot;&gt;
&lt;FormLabel component=&quot;legend&quot;&gt;
&lt;Typography variant=&quot;h4&quot;&gt; {data.data[0]?.questionText} &lt;/Typography&gt; 
&lt;/FormLabel&gt;
&lt;Box display=&quot;flex&quot; flex={1} gap={5}&gt;
{data?.data?.map((value, index) =&gt; {
return (
&lt;Box key={index} display=&quot;flex&quot; flex={1}&gt;
&lt;input
{...form.register(data?.questionCode, { required: true })}
type=&quot;radio&quot;
checked={valueChoice === `response-card-${value?.questionCode}-${index}`}
value={`${value.subSurvey}-${value.tag}-${index}`}
onChange={() =&gt; setValueChoice(`response-card-${value?.questionCode}-${index}`)}
id={`field-${data?.questionCode}-${index}`}
/&gt;
&lt;label
htmlFor={`field-${data?.questionCode}-${index}`}
key={index}
&gt;
&lt;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}
/&gt;
&lt;/label&gt;
&lt;/Box&gt;
);
})}
&lt;/Box&gt;
&lt;/FormControl&gt;
&lt;ActionButtons sizeQuestionnaire={sizeQuestionnaire} /&gt;
&lt;/form&gt;
);
};

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) =&gt; {
  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) =&gt; {
    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 (
    &lt;form onSubmit={form.handleSubmit(onSubmit)}&gt;
      &lt;FormControl component=&quot;fieldset&quot;&gt;
        &lt;FormLabel component=&quot;legend&quot;&gt;
          &lt;Typography variant=&quot;h4&quot;&gt; {data.data[0]?.questionText} &lt;/Typography&gt;
        &lt;/FormLabel&gt;
        &lt;Box display=&quot;flex&quot; flex={1} gap={5}&gt;
          {data?.data?.map((value, index) =&gt; {
            return (
              &lt;Box key={index} display=&quot;flex&quot; flex={1}&gt;
                &lt;input
                  {...form.register(data?.questionCode, { required: true })}
                  type=&quot;radio&quot;
                  checked={valueChoice === `response-card-${value?.questionCode}-${index}`}
                  value={`${value.subSurvey}-${value.tag}-${index}`}
                  onChange={() =&gt; setValueChoice(`response-card-${value?.questionCode}-${index}`)}
                  id={`field-${data?.questionCode}-${index}`}
                /&gt;
                &lt;label htmlFor={`field-${data?.questionCode}-${index}`} key={index}&gt;
                  &lt;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}
                  /&gt;
                &lt;/label&gt;
              &lt;/Box&gt;
            );
          })}
        &lt;/Box&gt;
      &lt;/FormControl&gt;
      &lt;ActionButtons sizeQuestionnaire={sizeQuestionnaire} /&gt;
    &lt;/form&gt;
  );
};

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) =&gt; {
    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) =&gt; {
  const form = useForm({ shouldUnregister: true });
  const { state } = useStateMachine();
  const [valueChoice, setValueChoice] = useState(state[data?.questionCode]);

  /* ------------- PART IN QUESTIONS */

  const onSubmit = useOnSubmit();

  return (
    &lt;form onSubmit={form.handleSubmit(onSubmit)}&gt;
      ...
    &lt;/form&gt;
  );
};

huangapple
  • 本文由 发表于 2023年6月12日 16:32:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/76454843.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定