Skip to content

Commit 221919c

Browse files
committed
fix(clerk-react): Make isomorphicClerk loading idempotent
1 parent cb777d4 commit 221919c

File tree

3 files changed

+26
-26
lines changed

3 files changed

+26
-26
lines changed

packages/react/src/contexts/ClerkContextProvider.tsx

+17-7
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,24 @@
11
import { ActiveSessionResource, ClientResource, InitialState, Resources, UserResource } from '@clerk/types';
22
import React from 'react';
33

4-
import IsomorphicClerk from '../isomorphicClerk';
4+
import IsomorphicClerk, { NewIsomorphicClerkParams } from '../isomorphicClerk';
55
import { AuthContext } from './AuthContext';
66
import { ClientContext } from './ClientContext';
77
import { IsomorphicClerkContext } from './IsomorphicClerkContext';
88
import { SessionContext } from './SessionContext';
99
import { UserContext } from './UserContext';
1010

11-
type ClerkContextWrapperProps = {
12-
isomorphicClerk: IsomorphicClerk;
11+
type ClerkContextProvider = {
12+
isomorphicClerkOptions: NewIsomorphicClerkParams;
1313
initialState: InitialState | undefined;
1414
children: React.ReactNode;
15-
clerkLoaded: boolean;
1615
};
1716

1817
type ClerkContextProviderState = Resources;
1918

20-
export function ClerkContextProvider(props: ClerkContextWrapperProps): JSX.Element | null {
21-
const { isomorphicClerk, children, clerkLoaded, initialState } = props;
22-
const clerk = isomorphicClerk;
19+
export function ClerkContextProvider(props: ClerkContextProvider): JSX.Element | null {
20+
const { isomorphicClerkOptions, initialState, children } = props;
21+
const { isomorphicClerk: clerk, loaded: clerkLoaded } = useLoadedIsomorphicClerk(isomorphicClerkOptions);
2322

2423
const [state, setState] = React.useState<ClerkContextProviderState>({
2524
client: clerk.client as ClientResource,
@@ -62,6 +61,17 @@ export function ClerkContextProvider(props: ClerkContextWrapperProps): JSX.Eleme
6261
);
6362
}
6463

64+
const useLoadedIsomorphicClerk = (options: NewIsomorphicClerkParams) => {
65+
const [loaded, setLoaded] = React.useState(false);
66+
const isomorphicClerk = React.useMemo(() => IsomorphicClerk.getOrCreateInstance(options), []);
67+
68+
React.useEffect(() => {
69+
isomorphicClerk.addOnLoaded(() => setLoaded(true));
70+
}, []);
71+
72+
return { isomorphicClerk, loaded };
73+
};
74+
6575
// This should be provided from isomorphicClerk
6676
// TODO: move inside isomorphicClerk
6777
function deriveState(

packages/react/src/contexts/ClerkProvider.tsx

+5-16
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { InitialState } from '@clerk/types';
2-
import React, { useEffect, useMemo, useState } from 'react';
2+
import React from 'react';
33

44
import { multipleClerkProvidersError } from '../errors';
5-
import IsomorphicClerk from '../isomorphicClerk';
65
import type { IsomorphicClerkOptions } from '../types';
76
import { withMaxAllowedInstancesGuard } from '../utils';
87
import { ClerkContextProvider } from './ClerkContextProvider';
@@ -15,25 +14,15 @@ export interface ClerkProviderProps extends IsomorphicClerkOptions {
1514
}
1615

1716
function ClerkProviderBase(props: ClerkProviderProps): JSX.Element {
18-
const [clerkLoaded, setClerkLoaded] = useState(false);
19-
20-
const clerk = useMemo(() => {
21-
const { frontendApi = '', Clerk: ClerkConstructor, ...options } = props;
22-
return IsomorphicClerk.getOrCreateInstance({ frontendApi, options, Clerk: ClerkConstructor });
23-
}, []);
24-
25-
useEffect(() => {
26-
void clerk.loadClerkJS().then(() => setClerkLoaded(true));
27-
}, []);
17+
const { initialState, children, Clerk, frontendApi, ...options } = props;
2818

2919
return (
3020
<StructureContext.Provider value={StructureContextStates.noGuarantees}>
3121
<ClerkContextProvider
32-
initialState={props.initialState}
33-
isomorphicClerk={clerk}
34-
clerkLoaded={clerkLoaded}
22+
initialState={initialState}
23+
isomorphicClerkOptions={{ frontendApi: frontendApi || '', Clerk, options }}
3524
>
36-
{props.children}
25+
{children}
3726
</ClerkContextProvider>
3827
</StructureContext.Provider>
3928
);

packages/react/src/isomorphicClerk.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,14 @@ type MethodName<T> = {
3434
}[keyof T];
3535
type MethodCallback = () => void;
3636

37-
type NewIsomorphicClerkParams = {
37+
export type NewIsomorphicClerkParams = {
3838
frontendApi: string;
3939
options: IsomorphicClerkOptions;
4040
Clerk: ClerkProp | null;
4141
};
4242

4343
export default class IsomorphicClerk {
44-
private mode: string;
44+
private mode: 'browser' | 'server';
4545
private frontendApi: string;
4646
private options: IsomorphicClerkOptions;
4747
private Clerk: ClerkProp;
@@ -80,10 +80,11 @@ export default class IsomorphicClerk {
8080
this.options = options;
8181
this.Clerk = Clerk;
8282
this.mode = inClientSide() ? 'browser' : 'server';
83+
void this.loadClerkJS();
8384
}
8485

8586
async loadClerkJS(): Promise<BrowserClerk | undefined> {
86-
if (this.#loaded) {
87+
if (this.mode !== 'browser' || this.#loaded) {
8788
return;
8889
}
8990

0 commit comments

Comments
 (0)