useLoadedIsomorphicClerk misses "ready" when a ClerkProvider remounts after clerk-js has loaded — <ClerkLoading> never resolves

Offen Anfängerfreundlich
#10,462 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Maintainer antworten meist innerhalb von 1 Tag

Dieses Issue hat noch niemand übernommen.

  • #10465 von @umeraamir69 — ohne Merge geschlossen

Bewertung

Schwierigkeit
2/5
Geschätzter Aufwand
1-3 Stunden
Anfängerfreundlichkeit
82/100
Issue-Typ
Bug
Klarheit
Klar beschrieben
Aktivitätsstatus
Aktiv

Rechercherichtung

Beginne in @clerk/react bei useLoadedIsomorphicClerk: Vergleiche das on("status", …)-Abonnement des Effects mit replayInterceptedInvocations, das { notify: true } übergibt. Reproduziere das mit zwei Route-Group-Layouts unter app/[locale]/(auth)/layout.tsx, indem du nach dem Bereitsein von clerk-js clientseitig hinaus- und wieder zurücknavigierst; der zweite Mount sollte <ClerkLoaded> statt des <ClerkLoading>-Skeletons rendern. Füge die Hook-/Provider-Tests des Pakets hinzu oder führe sie aus, falls vorhanden, und decke die Remount-Race ab.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Beschreibung

Packages
  • @clerk/react 6.14.5 (also checked: 6.1.3 and 6.18.2 — same code), via @clerk/nextjs 7.2.4
  • clerk-js 6.41.0 / @clerk/ui 1.42.0 (also reproduced with clerk-js 6.30.0 – 6.40.1)
  • Next.js 16.4 App Router, React 19.2
What happens

A ClerkProvider mounted in a route-group layout (e.g. app/[locale]/(auth)/layout.tsx) unmounts when the user navigates client-side to a page outside that layout, and mounts again when they navigate back (client-side). On the second mount, <ClerkLoading> stays rendered forever and <ClerkLoaded> never renders, although window.Clerk.loaded === true and window.Clerk.status === "ready". A full page load always works.

Reproduction
  1. Layout A renders <ClerkProvider> + <ClerkLoading>skeleton</ClerkLoading><ClerkLoaded><SignIn /></ClerkLoaded>; layout B has no provider.
  2. Load a page under B, navigate client-side (<Link> / router.push) to the page under A → <SignIn /> mounts.
  3. Navigate client-side back to B, then client-side to A again → the skeleton stays.

It is a race, so it does not fire every time: with a <Link> click it hung 12/12 in headless Chrome, with router.push 2 of 3.

Cause

In useLoadedIsomorphicClerk:

const isomorphicClerkRef = React.useRef(IsomorphicClerk.getOrCreateInstance(optionsWithDefaults));
const [clerkStatus, setClerkStatus] = React.useState(isomorphicClerkRef.current.status);
React.useEffect(() => {
  isomorphicClerkRef.current.on("status", setClerkStatus);
  return () => { /* off + */ IsomorphicClerk.clearInstance(); };
}, []);
  • The unmount clears the singleton, so the second mount creates a new IsomorphicClerk whose status starts at "loading".
  • getEntryChunks() finds the already-loaded window.Clerk, skips load() and calls replayInterceptedInvocations(). That transfers early status listeners to clerk-js with { notify: true }, but emits "ready" itself only when clerkjs.status is undefined — clerk-js is already "ready" and emits nothing new.
  • If the effect subscribes after the replay (the replay resolves within microtasks when clerk-js is loaded), on("status", …) goes straight to clerkjs.on without notify, so the hook never receives the current status. ClerkContextProvider memoises the context value on clerkStatus, so no consumer re-renders.
Suggested fix
- isomorphicClerkRef.current.on("status", setClerkStatus);
+ isomorphicClerkRef.current.on("status", setClerkStatus, { notify: true });

This is the same option replayInterceptedInvocations already uses. We verified it by serving our production chunk with only this change: the widget mounted 5/5 times on the second client-side visit, versus the skeleton 5/5 times with the original chunk. We currently apply the one-line change to the installed package at build time as a workaround.

Vorherrschende Sprache
TypeScript
Sterne
1.8k
Forks
492
Ø Merge
1 T. 6 Std.
Gemergte PRs (30 T.)
367

Entwicklungsumgebung

Erste Schritte

  1. Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
  3. Forken Sie das Repository und arbeiten Sie in einem Branch.
  4. Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.

Mehr aus clerk/javascript

Alle Issues in clerk/javascript

Ähnliche Issues

Weitere Issues zu TypeScript

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.