|
1 | 1 | import { isClerkRuntimeError } from '@clerk/shared/error'; |
2 | | -import { useEffect, useMemo, useState } from 'react'; |
| 2 | +import { useEffect, useMemo } from 'react'; |
3 | 3 |
|
4 | 4 | import type { FlowDirection } from '../../components/flow'; |
| 5 | +import { useNow } from '../../hooks/use-now'; |
5 | 6 | import type { ErrorDescription } from '../../localization'; |
6 | 7 | import { useErrorText, useMessages } from '../../localization'; |
7 | 8 | import { setup } from '../../machine/setup'; |
@@ -538,19 +539,11 @@ function useReverificationState(model: ReverificationModel): ReverificationContr |
538 | 539 | : undefined, |
539 | 540 | ); |
540 | 541 |
|
541 | | - const [now, setNow] = useState(() => Date.now()); |
542 | 542 | const resendAvailableAt = snapshot.context.resendAvailableAt; |
| 543 | + const now = useNow({ updateInterval: resendAvailableAt === undefined ? undefined : 1000 }).getTime(); |
543 | 544 | const canResend = resendAvailableAt === undefined || now >= resendAvailableAt; |
544 | 545 | const countingDown = !canResend; |
545 | 546 |
|
546 | | - useEffect(() => { |
547 | | - if (!countingDown) { |
548 | | - return; |
549 | | - } |
550 | | - const id = window.setInterval(() => setNow(Date.now()), 1000); |
551 | | - return () => window.clearInterval(id); |
552 | | - }, [countingDown, resendAvailableAt]); |
553 | | - |
554 | 547 | const cancelModel = |
555 | 548 | (model.status === 'loading' || model.status === 'active') && snapshot.value !== 'retrying' |
556 | 549 | ? model.cancel |
@@ -622,12 +615,6 @@ function useReverificationState(model: ReverificationModel): ReverificationContr |
622 | 615 | otpChannel: activeMethod ? otpChannelFor(activeMethod.strategy) : undefined, |
623 | 616 | onResend: () => send({ type: 'RESEND' }), |
624 | 617 | canResend, |
625 | | - // We clamp this to 30s because the first render after locking resend |
626 | | - // will have the old `now` state set, which would result in a value above |
627 | | - // 30s. There are other solutions like reading Date.now() in render and |
628 | | - // letting the interval only retrigger render, but that makes the render |
629 | | - // impure which is something the React compiler would warn about. |
630 | | - // useSyncExternalStore feels unnecessarily complex here |
631 | 618 | resendRemainingSeconds: |
632 | 619 | countingDown && resendAvailableAt |
633 | 620 | ? Math.min(RESEND_COOLDOWN_MS / 1000, Math.max(0, Math.ceil((resendAvailableAt - now) / 1000))) |
|
0 commit comments