From 0266f6a73fc34748a86603bc89b6125d6bbb679b Mon Sep 17 00:00:00 2001 From: Jacek Radko Date: Tue, 10 Dec 2024 09:24:11 -0600 Subject: [PATCH] fix(clerk-react): Use derived state over local state in useAuth (#4715) --- .changeset/red-cats-approve.md | 5 ++++ .../src/hooks/__tests__/useAuth.test.tsx | 24 +++++++++++++++++++ ...{useAuth.test.ts => useAuth.types.test.ts} | 0 packages/react/src/hooks/useAuth.ts | 24 ++++++------------- 4 files changed, 36 insertions(+), 17 deletions(-) create mode 100644 .changeset/red-cats-approve.md create mode 100644 packages/react/src/hooks/__tests__/useAuth.test.tsx rename packages/react/src/hooks/__tests__/{useAuth.test.ts => useAuth.types.test.ts} (100%) diff --git a/.changeset/red-cats-approve.md b/.changeset/red-cats-approve.md new file mode 100644 index 0000000000..2926ba3192 --- /dev/null +++ b/.changeset/red-cats-approve.md @@ -0,0 +1,5 @@ +--- +'@clerk/clerk-react': patch +--- + +`useAuth` now uses derived auth state instead of locally stored state diff --git a/packages/react/src/hooks/__tests__/useAuth.test.tsx b/packages/react/src/hooks/__tests__/useAuth.test.tsx new file mode 100644 index 0000000000..5b78c7c836 --- /dev/null +++ b/packages/react/src/hooks/__tests__/useAuth.test.tsx @@ -0,0 +1,24 @@ +import { render } from '@testing-library/react'; +import React from 'react'; + +import { useAuth } from '../useAuth'; + +const TestComponent = () => { + const { isLoaded, isSignedIn } = useAuth(); + return ( +
+ {isLoaded} + {isSignedIn} +
+ ); +}; + +describe('useAuth', () => { + test('throws an error if not wrapped in ', () => { + expect(() => { + render(); + }).toThrow( + '@clerk/clerk-react: useAuth can only be used within the component. Learn more: https://clerk.com/docs/components/clerk-provider', + ); + }); +}); diff --git a/packages/react/src/hooks/__tests__/useAuth.test.ts b/packages/react/src/hooks/__tests__/useAuth.types.test.ts similarity index 100% rename from packages/react/src/hooks/__tests__/useAuth.test.ts rename to packages/react/src/hooks/__tests__/useAuth.types.test.ts diff --git a/packages/react/src/hooks/useAuth.ts b/packages/react/src/hooks/useAuth.ts index d666c50d23..bb3a56a4d6 100644 --- a/packages/react/src/hooks/useAuth.ts +++ b/packages/react/src/hooks/useAuth.ts @@ -1,6 +1,6 @@ import { createCheckAuthorization } from '@clerk/shared/authorization'; import type { CheckAuthorizationWithCustomPermissions, GetToken, SignOut, UseAuthReturn } from '@clerk/types'; -import { useCallback, useEffect, useState } from 'react'; +import { useCallback } from 'react'; import { useAuthContext } from '../contexts/AuthContext'; import { useIsomorphicClerkContext } from '../contexts/IsomorphicClerkContext'; @@ -50,24 +50,14 @@ type UseAuth = (initialAuthState?: any) => UseAuthReturn; export const useAuth: UseAuth = (initialAuthState = {}) => { useAssertWrappedByClerkProvider('useAuth'); - const authContext = useAuthContext(); + const authContextFromHook = useAuthContext(); + let authContext = authContextFromHook; - const [authState, setAuthState] = useState(() => { - // This indicates the authContext is not available, and so we fallback to the provided initialState - if (authContext.sessionId === undefined && authContext.userId === undefined) { - return initialAuthState ?? {}; - } - return authContext; - }); - - useEffect(() => { - if (authContext.sessionId === undefined && authContext.userId === undefined) { - return; - } - setAuthState(authContext); - }, [authContext]); + if (authContext.sessionId === undefined && authContext.userId === undefined) { + authContext = initialAuthState != null ? initialAuthState : {}; + } - const { sessionId, userId, actor, orgId, orgRole, orgSlug, orgPermissions, factorVerificationAge } = authState; + const { sessionId, userId, actor, orgId, orgRole, orgSlug, orgPermissions, factorVerificationAge } = authContext; const isomorphicClerk = useIsomorphicClerkContext(); const getToken: GetToken = useCallback(createGetToken(isomorphicClerk), [isomorphicClerk]);