diff --git a/.changeset/witty-cougars-tickle.md b/.changeset/witty-cougars-tickle.md new file mode 100644 index 00000000000..fcdf2054f0d --- /dev/null +++ b/.changeset/witty-cougars-tickle.md @@ -0,0 +1,5 @@ +--- +'@clerk/clerk-js': patch +--- + +Avoid triggering email code verification twice on React strict mode diff --git a/packages/clerk-js/src/ui/components/SignIn/SignInFactorOneCodeForm.tsx b/packages/clerk-js/src/ui/components/SignIn/SignInFactorOneCodeForm.tsx index 455633fa264..b0c4b5f988c 100644 --- a/packages/clerk-js/src/ui/components/SignIn/SignInFactorOneCodeForm.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/SignInFactorOneCodeForm.tsx @@ -1,12 +1,12 @@ import { isUserLockedError } from '@clerk/shared/error'; import { useClerk } from '@clerk/shared/react'; import type { EmailCodeFactor, PhoneCodeFactor, ResetPasswordCodeFactor } from '@clerk/types'; -import React from 'react'; import { clerkInvalidFAPIResponse } from '../../../core/errors'; import { useCoreSignIn, useSignInContext } from '../../contexts'; import type { VerificationCodeCardProps } from '../../elements'; import { useCardState, VerificationCodeCard } from '../../elements'; +import { useFetch } from '../../hooks'; import { useSupportEmail } from '../../hooks/useSupportEmail'; import type { LocalizationKey } from '../../localization'; import { useRouter } from '../../router'; @@ -37,23 +37,40 @@ export const SignInFactorOneCodeForm = (props: SignInFactorOneCodeFormProps) => const supportEmail = useSupportEmail(); const clerk = useClerk(); + const shouldAvoidPrepare = signIn.firstFactorVerification.status === 'verified' && props.factorAlreadyPrepared; + const goBack = () => { return navigate('../'); }; - React.useEffect(() => { - if (!props.factorAlreadyPrepared) { - prepare(); + const prepare = () => { + if (shouldAvoidPrepare) { + return; } - }, []); - const prepare = () => { void signIn .prepareFirstFactor(props.factor) .then(() => props.onFactorPrepare()) .catch(err => handleError(err, [], card.setError)); }; + useFetch( + shouldAvoidPrepare + ? undefined + : () => + signIn + ?.prepareFirstFactor(props.factor) + .then(() => props.onFactorPrepare()) + .catch(err => handleError(err, [], card.setError)), + { + name: 'signIn.prepareFirstFactor', + factor: props.factor, + }, + { + staleTime: 100, + }, + ); + const action: VerificationCodeCardProps['onCodeEntryFinishedAction'] = (code, resolve, reject) => { signIn .attemptFirstFactor({ strategy: props.factor.strategy, code })