Skip to content

Commit ba4c400

Browse files
authored
Merge pull request #174 from MeshJS/bug/wallet-connector
Implement retry logic for wallet detection in ConnectWallet component
2 parents 98390ac + df43c06 commit ba4c400

File tree

2 files changed

+82
-3
lines changed

2 files changed

+82
-3
lines changed

src/components/common/cardano-objects/connect-wallet.tsx

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
} from "@/components/ui/dropdown-menu";
1111
import { useWallet, useWalletList, useNetwork, useAssets } from "@meshsdk/react";
1212
import { useSiteStore } from "@/lib/zustand/site";
13-
import { useEffect } from "react";
13+
import { useEffect, useRef } from "react";
1414
import useUser from "@/hooks/useUser";
1515
import { useUserStore } from "@/lib/zustand/user";
1616
import { getProvider } from "@/utils/get-provider";
@@ -30,12 +30,86 @@ export default function ConnectWallet() {
3030
const networkId = useNetwork();
3131
const assets = useAssets();
3232
const network = useSiteStore((state) => state.network);
33+
const retryTimeoutRef = useRef<NodeJS.Timeout | null>(null);
34+
const retryCountRef = useRef(0);
35+
const walletsRef = useRef(wallets);
36+
37+
// Keep wallets ref in sync
38+
useEffect(() => {
39+
walletsRef.current = wallets;
40+
}, [wallets]);
3341

3442
async function connectWallet(walletId: string) {
3543
setPastWallet(walletId);
3644
await connect(walletId);
3745
}
3846

47+
// Retry wallet detection on mount to handle cached loads
48+
// Browser extensions inject wallets asynchronously, and cached scripts may load
49+
// before MeshProvider/wallet detection is fully initialized
50+
useEffect(() => {
51+
// If wallets are already detected, no need to retry
52+
if (wallets.length > 0) {
53+
retryCountRef.current = 0;
54+
if (retryTimeoutRef.current) {
55+
clearTimeout(retryTimeoutRef.current);
56+
retryTimeoutRef.current = null;
57+
}
58+
return;
59+
}
60+
61+
// Clear any existing timeout
62+
if (retryTimeoutRef.current) {
63+
clearTimeout(retryTimeoutRef.current);
64+
retryTimeoutRef.current = null;
65+
}
66+
67+
// Reset retry count
68+
retryCountRef.current = 0;
69+
70+
// Retry detection with increasing delays: immediate, 100ms, 500ms, 1000ms
71+
// This gives MeshProvider and browser extensions time to initialize
72+
const delays = [0, 100, 500, 1000];
73+
const maxRetries = delays.length;
74+
75+
const checkWallets = () => {
76+
// Check current wallets (using ref to avoid closure issues)
77+
if (walletsRef.current.length > 0) {
78+
retryCountRef.current = 0;
79+
if (retryTimeoutRef.current) {
80+
clearTimeout(retryTimeoutRef.current);
81+
retryTimeoutRef.current = null;
82+
}
83+
return;
84+
}
85+
86+
// If we've reached max retries, stop
87+
if (retryCountRef.current >= maxRetries) {
88+
retryCountRef.current = 0;
89+
return;
90+
}
91+
92+
// Schedule next retry
93+
const delay = delays[retryCountRef.current];
94+
retryCountRef.current++;
95+
96+
// Use setTimeout even for 0ms delay to avoid recursion issues
97+
retryTimeoutRef.current = setTimeout(checkWallets, delay);
98+
};
99+
100+
// Start checking immediately (using setTimeout with 0ms for next tick)
101+
retryTimeoutRef.current = setTimeout(checkWallets, 0);
102+
retryCountRef.current = 1;
103+
104+
return () => {
105+
if (retryTimeoutRef.current) {
106+
clearTimeout(retryTimeoutRef.current);
107+
retryTimeoutRef.current = null;
108+
}
109+
retryCountRef.current = 0;
110+
};
111+
}, [wallets.length]);
112+
39113
// Auto-connect if user had connected before
40114
useEffect(() => {
41115
if (pastWallet && !connected && wallets.length > 0) {

src/components/common/overall-layout/layout.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,14 @@ import { MobileNavigation } from "@/components/ui/mobile-navigation";
3030
import { MobileActionsMenu } from "@/components/ui/mobile-actions-menu";
3131

3232
// Dynamically import ConnectWallet with SSR disabled to avoid production SSR issues
33+
// Using a version-based key ensures fresh mount on updates, preventing cache issues
3334
const ConnectWallet = dynamic(
3435
() => import("@/components/common/cardano-objects/connect-wallet"),
35-
{ ssr: false }
36+
{
37+
ssr: false,
38+
// Force re-mount on navigation to handle cache issues
39+
loading: () => null,
40+
}
3641
);
3742

3843
// Enhanced error boundary component for wallet errors
@@ -261,7 +266,7 @@ export default function RootLayout({
261266
{/* Right: Control buttons */}
262267
<div className="ml-auto flex items-center gap-2">
263268
{!connected ? (
264-
<ConnectWallet />
269+
<ConnectWallet key="wallet-connector" />
265270
) : (
266271
<>
267272
{/* Desktop buttons */}

0 commit comments

Comments
 (0)