Crucial: How to integrate Wallet into NextJS v14 TypeScript?

All examples using FuelSDK is in Reactjs instead of Nextjs. I am facing problem integrating Fuel Wallet SDK into Typescript Next.js v14.

I adapted the code from Wallet Docs:

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

import { FuelProvider } from '@fuels/react';
import { defaultConnectors } from '@fuels/connectors';

const queryClient = new QueryClient();

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
  <React.StrictMode>
    <QueryClientProvider client={queryClient}>
      <FuelProvider fuelConfig={{ connectors: defaultConnectors({ devMode: true }) }}>
        <App />
      </FuelProvider>
    </QueryClientProvider>
  </React.StrictMode>
);

This is the error:

Error: (0 , react__WEBPACK_IMPORTED_MODULE_1__.createContext) is not a function

This is my implemented code in app/layout.tsx:

import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";

import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { FuelProvider } from '@fuels/react';
import { defaultConnectors } from '@fuels/connectors';

const inter = Inter({ subsets: ["latin"] });

const queryClient = new QueryClient();

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <QueryClientProvider client={queryClient}>
      <FuelProvider fuelConfig={{ connectors: defaultConnectors({ devMode: true }) }}>
        <html lang="en">
          <body className={inter.className}>
            {children}
          </body>
        </html>
      </FuelProvider>
    </QueryClientProvider>
  );
}
1 Like

Hey @eesheng, could you share if you’re using server-side rendering or not? I suspect that its trying to access context on the server side and as Context is not available on the server side, its throwing an error.

2 Likes

In NextJS 13 onwards, if the first line of code isn’t using “use client”, it will use server side rendering. I tried using it on Root Layout, albeit it affect processing and shouldn’t be used at all because developers unable to benefit from NextJS 13. Hence, to answer your question, yes, it uses server side rendering. Pretty sure it’s because of using the app router standard of NextJS 13 onwards hence causing the issue. Do clarify if I’m wrong.

1 Like

Just to test it out, I changed the wrapper into app/page.tsx. It instead pop out. What I’m trying to accomplish is creating a NextJS14 of swayswap. Most files are adapted from there, but I still think that it’s because the wallet require client side, but can’t add “use client” into app/layout.tsx.

Unhandled Runtime Error
Error: useFuel must be used within a FuelHooksProvider

Source
src/app/hooks/useBrowserWallet.tsx (13:31) @ useWallet

  11 |
  12 | export const useBrowserWallet: () => BrowserWallet = () => {
> 13 |   const { wallet } = useWallet();
     |                               ^
  14 |   const [browserWalletBalance, setBrowserWalletBalance] = useState<BN>();
  15 |   const { isConnected } = useIsConnected();
  16 |   const { network } = useNetwork();

This is just random trying. Do not be distracted by the error, focus on my previous post

1 Like

I manage to solve the issue with adding “use client” on top of app/layout.tsx. I think it is suboptimal since all rendering will be client side. Are all DEX build this way?

This is a poor solution albeit it works

I created a wrap provider using the client side rendering, I then wrap it in my layout.tsx to solve the issue without forfeiting the Nextjs v14 server-side rendering features:

// src/app/WrapProvider.tsx
'use client'
import { FuelProvider } from '@fuels/react';
import {
  FuelWalletConnector,
  FuelWalletDevelopmentConnector,
  FueletWalletConnector,
} from '@fuels/connectors';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

const queryClient = new QueryClient();

export default function WrapProvider({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <>
            <QueryClientProvider client={queryClient}>
      <FuelProvider
        fuelConfig={{
          connectors: [
            new FuelWalletConnector(),
            new FuelWalletDevelopmentConnector(),
            new FueletWalletConnector(),
          ],
        }}
      >
      {children}
      </FuelProvider>
    </QueryClientProvider>
    </>
  )
}

This is my src/app/layout.tsx. You will notice that metadata works instead of my previous solution.

import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import NavBar from "./components/organisms/NavBar";
import WrapProvider from "./WrapProvider";
import { ThemeContextProvider } from "@src/libs/state";

import { FuelProvider } from '@fuels/react';
import {
  FuelWalletConnector,
  FuelWalletDevelopmentConnector,
  FueletWalletConnector,
} from '@fuels/connectors';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <WrapProvider>
        {children}
        </WrapProvider>
        </body>
    </html>
  );
}

Adapted from: Error exporting ‘metadata’ from a component marked with ‘use client’ during Vercel deployment · vercel/next.js · Discussion #51002 · GitHub

P.S Do give a like hehe, spend a day solving this :stuck_out_tongue:

2 Likes

i am glad it worked out :slight_smile:

1 Like

This topic was automatically closed 20 days after the last reply. New replies are no longer allowed.