#RainbowKitProvider - QueryClient error

1 messages · Page 1 of 1 (latest)

covert otter
#
//app-providers
'use client';

import { SessionProvider } from 'next-auth/react';
import { ReactNode } from 'react';

import IntlProvider from './intl-provider';
import PrefetchUser from './prefetch-user';
import SidebarProvider from './sidebar-provider';
import ThemeProvider from './theme-provider';
import { Web3Provider } from './wallet-providers';

interface AppProvidersProps {
  children: ReactNode;
}

const AppProviders = ({ children }: AppProvidersProps) => {
  return (
    <SessionProvider>
      <Web3Provider>
        <PrefetchUser>
          <ThemeProvider>
            <IntlProvider>
              <SidebarProvider>{children}</SidebarProvider>
            </IntlProvider>
          </ThemeProvider>
        </PrefetchUser>
      </Web3Provider>
    </SessionProvider>
  );
};

export default AppProviders;

//wallet-providers
'use client';

import { RainbowKitProvider, darkTheme } from '@rainbow-me/rainbowkit';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactNode, useState } from 'react';
import { WagmiProvider } from 'wagmi';

import { wagmiConfig } from '@/lib/utils/wagmi-config';

// Rainbow Kit theme
const rainbowKitTheme = {
  accentColor: '#0E76FD',
  accentColorForeground: 'white',
};

export const Web3Provider = ({ children }: { children: ReactNode }) => {
  const [queryClient] = useState(
    () =>
      new QueryClient({
        defaultOptions: {
          queries: {
            staleTime: 60 * 1000,
          },
        },
      })
  );

  return (
    <WagmiProvider config={wagmiConfig}>
      <QueryClientProvider client={queryClient}>
        <RainbowKitProvider theme={darkTheme(rainbowKitTheme)}>
          {children}
        </RainbowKitProvider>
      </QueryClientProvider>
    </WagmiProvider>
  );
};

Why I got this error: "Error: No QueryClient set, use QueryClientProvider to set one" when running my code in dev mode
in build mode build is good but start will got an error

copper violetBOT
#

Hi @covert otter. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

The error you're experiencing with "No QueryClient set, use QueryClientProvider to set one" is related to how client components are rendered in Next.js, particularly when using React Query with the App Router.

The Issue

The problem occurs because of how Next.js handles client components during server-side rendering. When using React Query in a client component, the QueryClient instance might not be properly initialized or accessible during the server rendering phase, even though you've set it up correctly in your code.

This is a common issue when using third-party libraries like TanStack Query (React Query) with Next.js, especially in development mode.

Why It Happens

Looking at your code, you're creating a QueryClient inside a client component (Web3Provider), which is the correct approach. However, there are a few potential issues:

  1. The error suggests that somewhere in your application, a component is trying to use a query hook before the QueryClient is available.

  2. This is particularly problematic in Next.js because of how it handles server components and client components differently.

  3. According to the knowledge sources, there's a specific issue with React Query using Date.now() instead of the performance API, which can cause problems with Next.js's dynamic rendering as mentioned in this GitHub issue.

Solutions

Here are some approaches to fix this issue:

1. Update React Query Version

The issue has been fixed in TanStack Query v5.62.12. Make sure you're using this version or newer:

npm install @tanstack/react-query@latest

2. Modify Your QueryClient Provider

Try wrapping your QueryClient in a separate client component:

'use client';
#

import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { useState } from 'react';

export default function QueryProvider({ children }) {
const [queryClient] = useState(() => new QueryClient({
defaultOptions: {
queries: {
staleTime: 60 * 1000,
},
},
}));

return (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
);
}


Then use this component in your `Web3Provider`:

```tsx
import QueryProvider from './query-provider';

export const Web3Provider = ({ children }: { children: ReactNode }) => {
  return (
    <WagmiProvider config={wagmiConfig}>
      <QueryProvider>
        <RainbowKitProvider theme={darkTheme(rainbowKitTheme)}>
          {children}
        </RainbowKitProvider>
      </QueryProvider>
    </WagmiProvider>
  );
};

3. Ensure Proper Context Provider Order

According to the Next.js documentation on using context providers, you should render providers as deep as possible in the tree. Make sure your providers are properly nested and that any component using React Query hooks is within the QueryClientProvider.

4. Use Suspense for Provider Initialization

As mentioned in one of the GitHub issues, wrapping your provider in Suspense might help:

import { Suspense } from 'react';

// In your layout or page
<Suspense fallback={<LoadingSpinner />}>
  <Web3Provider>
    {children}
  </Web3Provider>
</Suspense>

Note that this approach might opt your entire subtree into client-side rendering only.

Why It Works in Build But Not in Dev/Start

#

This discrepancy between development and production environments is common with Next.js. The development server uses different optimization strategies and hot module replacement, which can expose issues that might not appear in production builds.

However, if you're seeing errors when running next start after a successful build, it suggests that there might be runtime issues with how the QueryClient is initialized or accessed in the production environment.

Make sure to check the version of React Query you're using and consider updating to the latest version, as the issue with Date.now() has been fixed in recent releases.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@covert otter Kapa.ai is still learning and improving, please let me know how I did by reacting below.

covert otter
#

WalletConnect Core is already initialized. This is probably a mistake and can lead to unexpected behavior. Init() was called 2 times.
⨯ Error: No QueryClient set, use QueryClientProvider to set one
at useConnect (../../../src/hooks/useConnect.ts:67:57) {
digest: '3925453674'
}
GET / 500 in 13422ms
○ Compiling /favicon.ico ...
GET /favicon.ico 200 in 1503ms
GET /favicon.ico 200 in 358ms
✓ Compiled /favicon.ico in 6.7s
⨯ Error: No QueryClient set, use QueryClientProvider to set one
at useConnect (../../../src/hooks/useConnect.ts:67:57) {
digest: '3925453674'
}
GET /src/hooks/useConnect.ts 500 in 7134ms
[ResponseAborted: ]
[ResponseAborted: ]
⨯ Error: No QueryClient set, use QueryClientProvider to set one
at useConnect (../../../src/hooks/useConnect.ts:67:57) {
digest: '3925453674'
}
GET /sw.js 500 in 6852ms
[ResponseAborted: ]
[ResponseAborted: ]
⨯ Error: No QueryClient set, use QueryClientProvider to set one
at useConnect (../../../src/hooks/useConnect.ts:67:57) {
digest: '3925453674'
}
GET /sw.js 500 in 1374ms
[ResponseAborted: ]
[ResponseAborted: ]

@copper violet

copper violetBOT
#

Let me check the knowledge base for you again. Give me one moment! :books:

#

Based on the error logs you've shared, you're experiencing two related issues with your Next.js application:

  1. "WalletConnect Core is already initialized" - indicating multiple initializations
  2. "No QueryClient set, use QueryClientProvider to set one" - suggesting React Query context issues

These errors are consistent with the singleton initialization problems that have been documented in Next.js, particularly when using client components with libraries that rely on global state.

The Root Cause

Looking at the knowledge sources, this appears to be related to how Next.js handles module loading and React contexts. There are several GitHub issues that describe similar problems:

  1. The error about "Cannot read properties of null (reading 'useContext')" is related to how React Query is initialized in Next.js as seen in this issue.

  2. Next.js can create multiple instances of what should be singleton objects due to its module loading system. As explained in this GitHub issue, Next.js uses different module systems (CJS for server context and webpack for browser context), which can cause initialization code to run multiple times.

Solutions

Here are some approaches to fix these issues:

1. Update TanStack Query

Make sure you're using the latest version of TanStack Query (v5.62.12 or newer), which includes fixes for Next.js compatibility issues:

npm install @tanstack/react-query@latest

2. Modify Your QueryClient Provider

Instead of initializing the QueryClient in a component with useState, try using a more stable approach:

'use client';
#

// Create a singleton QueryClient instance outside of component rendering
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 60 * 1000,
},
},
});

export const Web3Provider = ({ children }: { children: ReactNode }) => {
return (
<WagmiProvider config={wagmiConfig}>
<QueryClientProvider client={queryClient}>
<RainbowKitProvider theme={darkTheme(rainbowKitTheme)}>
{children}
</RainbowKitProvider>
</QueryClientProvider>
</WagmiProvider>
);
};


### 3. Use Suspense to Delay Initialization

As mentioned in one of the GitHub issues, wrapping your provider in Suspense might help:

```tsx
import { Suspense } from 'react';

// In your layout component
<Suspense fallback={<LoadingSpinner />}>
  <Web3Provider>
    {children}
  </Web3Provider>
</Suspense>

4. Address WalletConnect Initialization

For the WalletConnect initialization issue, you need to ensure it's only initialized once. This might require modifying your wagmi configuration to use a singleton pattern:

// In a separate file (e.g., wagmi-config.ts)
let wagmiConfigInstance;

export function getWagmiConfig() {
  if (!wagmiConfigInstance) {
    // Initialize WalletConnect and create wagmi config here
    wagmiConfigInstance = createConfig({
      // Your configuration
    });
  }
  return wagmiConfigInstance;
}

Then use this function in your Web3Provider:

import { getWagmiConfig } from '@/lib/utils/wagmi-config';

export const Web3Provider = ({ children }: { children: ReactNode }) => {
  const wagmiConfig = getWagmiConfig();
  // Rest of your component
}

Why This Happens

#

According to the knowledge sources, Next.js creates multiple workers during build and development, which can cause initialization code to run multiple times. Additionally, the way Next.js handles client components can lead to React context issues, especially with libraries that rely on global state like React Query and WalletConnect.

This is a known limitation with Next.js's architecture, particularly with the App Router, and various workarounds are being developed by the community.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@covert otter Kapa.ai is still learning and improving, please let me know how I did by reacting below.

covert otter
#

'use client';

import { RainbowKitProvider, darkTheme } from '@rainbow-me/rainbowkit';
import { ReactNode } from 'react';
import { WagmiProvider } from 'wagmi';

import { getWagmiConfig } from '@/lib/utils/wagmi-config';

export const WagmiAppProvider = ({ children }: { children: ReactNode }) => {
const wagmiConfig = getWagmiConfig();
return <WagmiProvider config={wagmiConfig}>{children}</WagmiProvider>;
};

// Rainbow Kit
const rainbowKitTheme = {
accentColor: '#0E76FD',
accentColorForeground: 'white',
};

export const RainbowKitAppProvider = ({
children,
}: {
children: ReactNode;
}) => {
return (
<RainbowKitProvider modalSize='compact' theme={darkTheme(rainbowKitTheme)}>
{children}
</RainbowKitProvider>
);
};

import { getDefaultConfig } from '@rainbow-me/rainbowkit';
import { Config } from 'wagmi';
import { arbitrum, base, mainnet, optimism, polygon } from 'wagmi/chains';

import { clientEnv } from '@/config/client-env';

let wagmiConfigInstance: Config | undefined;

export function getWagmiConfig() {
console.log('getWagmiConfig', wagmiConfigInstance);
if (!wagmiConfigInstance) {
wagmiConfigInstance = getDefaultConfig({
appName: '',
projectId: clientEnv.NEXT_PUBLIC_RAINBOW_KIT_PROJECT_ID,
chains: [mainnet, polygon, optimism, arbitrum, base],
ssr: true,
});
}
return wagmiConfigInstance;
}

@copper violet I made this but always WalletConnect Core is already initialized. This is probably a mistake and can lead to unexpected behavior. Init() was called 3 times.
ps: I remove the name it's voluntary to not show you the name

copper violetBOT
#

Let me check the knowledge base for you again. Give me one moment! :books:

#

I can see you're still experiencing the "WalletConnect Core is already initialized" error despite your changes to implement a singleton pattern for the wagmi configuration. This is a common issue with Next.js and relates directly to how modules are loaded and initialized in the framework.

The Root Issue

Based on the knowledge sources, this is happening because Next.js can initialize the same module multiple times in different contexts. As explained in this GitHub issue, Next.js uses different module systems (CJS for server context and webpack for browser context), which causes your singleton pattern to fail.

A user in one of the issues explains: "The reason you see your initialization logic occurring more than once is due to Next internally using two different module systems, CJS for the server context, and webpack for the browser context."

Why Your Current Solution Isn't Working

Your implementation of getWagmiConfig() with the singleton pattern is correct in principle, but it's not working because:

  1. Next.js is creating multiple instances of what should be a singleton
  2. The wagmiConfigInstance variable is being reset between different module loads
  3. This is particularly problematic with client components in the App Router

Possible Solutions

Here are some approaches that might help:

1. Use globalThis for Your Singleton

let wagmiConfigInstance: Config | undefined;
#

export function getWagmiConfig() {
if (!globalThis.wagmiConfigInstance) {
console.log('Initializing WagmiConfig for the first time');
globalThis.wagmiConfigInstance = getDefaultConfig({
appName: '',
projectId: clientEnv.NEXT_PUBLIC_RAINBOW_KIT_PROJECT_ID,
chains: [mainnet, polygon, optimism, arbitrum, base],
ssr: true,
});
}
return globalThis.wagmiConfigInstance;
}


### 2. Use the `instrumentation.ts` File

Next.js provides an `instrumentation.ts` file that runs only once during initialization. You could set up your WagmiConfig there:

```typescript
// instrumentation.ts
export function register() {
  if (process.env.NEXT_RUNTIME === 'nodejs') {
    // Initialize your WagmiConfig here
    const { getDefaultConfig } = require('@rainbow-me/rainbowkit');
    const { mainnet, polygon, optimism, arbitrum, base } = require('wagmi/chains');
    
    globalThis.wagmiConfigInstance = getDefaultConfig({
      appName: '',
      projectId: process.env.NEXT_PUBLIC_RAINBOW_KIT_PROJECT_ID,
      chains: [mainnet, polygon, optimism, arbitrum, base],
      ssr: true,
    });
  }
}

Then in your component:

export function getWagmiConfig() {
  return globalThis.wagmiConfigInstance;
}

3. Disable Parallel Building

You can try disabling parallel building in your next.config.js:

const nextConfig = {
  experimental: {
    webpackBuildWorker: false
  }
}

module.exports = nextConfig;

However, according to the knowledge sources, this might not completely solve the issue.

4. Use Environment Variables for Shared State

As suggested by a contributor in one of the issues:

if (!process.env.WAGMI_CONFIG_INITIALIZED) {
  // Initialize your config
  process.env.WAGMI_CONFIG_INITIALIZED = 'true';
}

Conclusion

#

This is a known limitation with Next.js's architecture, particularly with the App Router. The most reliable solution seems to be using globalThis combined with careful initialization checks. However, be aware that even this approach might not work perfectly in all scenarios due to how Next.js handles module loading.

If these solutions don't work, you might need to consider a more drastic approach, such as initializing WalletConnect in a completely separate process or service that Next.js interacts with, rather than trying to maintain a singleton within the Next.js application itself.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: