0

I was trying to load CoinbaseWalletSDK in my NextJS application, but it always throw an error of ReferenceError: localStorage is not defined due to it was imported before the window is loaded. I tried dynamic loading but it doesn't work. The following is what I am using at this moment.

export async function getServerSideProps({
  params,
}: {
  params: { project_id: string };
}) {

  const project_id = params.project_id;

  let project: any = fakeProjects[0];
  if (project_id && typeof project_id === 'string' && !isNaN(parseInt(project_id))) {
    const id = project_id;
    project = fakeProjects.find(p => p.id === parseInt(id));

    // Fetch project detail here
    let item = await (
      getNFTStatsByProjectId(
        parseInt(project_id)
      )
    );
    if (project && item && item['nftTotal'] && item['nftSold']) {
      if (item.nftSold > item.nftTotal) {
        item.nftSold = item.nftTotal;
      }
      project.nftTotal = item.nftTotal;
      project.nftSold = item.nftSold;
    }
  }
  
  const { coinbaseEth } = (await import('../../components/services/coinbase'));

  return {
    props: { 
      project: project,
      coinbaseEth: coinbaseEth
    },
  };
}

And this is what I have in the coinbase service:

// TypeScript
import CoinbaseWalletSDK from '@coinbase/wallet-sdk'
import Web3 from 'web3'

const APP_NAME = 'Practice App'
const APP_LOGO_URL = process.env.WEBSITE_URL + '/logo.png'
const DEFAULT_ETH_JSONRPC_URL = 'https://mainnet.infura.io/v3/' + process.env.INFURA_PROJECT_ID
const DEFAULT_CHAIN_ID = 1

// Initialize Coinbase Wallet SDK
export const coinbaseWallet = new CoinbaseWalletSDK({
  appName: APP_NAME,
  appLogoUrl: APP_LOGO_URL,
  darkMode: false
})

// Initialize a Web3 Provider object
export const coinbaseEth = coinbaseWallet.makeWeb3Provider(DEFAULT_ETH_JSONRPC_URL, DEFAULT_CHAIN_ID)

// Initialize a Web3 object
export const web3 = new Web3(coinbaseEth as any)

The new CoinbaseWalletSDK is where the error was thrown if that's a concern.

Based on my research, I will need to get it imported after the page is fully loaded (which is the point when "window" become available, as well as "localStorage"), which I have no clue how to achieve. Can anyone help me out on this?

TylerH
  • 20,799
  • 66
  • 75
  • 101
Terry Windwalker
  • 1,343
  • 2
  • 16
  • 36
  • `getServerSideProps` runs on the server, you can't access `localStorage` from it. You should move the logic that uses `coinbaseEth` to your page component inside `useEffect` to ensure it only runs on the client-side. – juliomalves Jul 19 '22 at 22:47
  • @juliomalves Adding it inside useEffect would cause the value being lost every time it renders, which prevents the variable becomes available. Is there a better way to achieve it? – Terry Windwalker Jul 20 '22 at 08:18
  • _"Adding it inside useEffect would cause the value being lost every time it renders"_ - What value? Can you not persist the value on the client if you need to? – juliomalves Jul 20 '22 at 08:52

1 Answers1

0

I solved it by loading it later. What I did was to assign this variable with this function.

  setTimeout(async () => {
    coinbaseEth = (await import('../../components/services/coinbase')).coinbaseEth;
  }, 1000)

I choose not to use useEffect because the value will be lost on render, which prevents the function to work properly.

Terry Windwalker
  • 1,343
  • 2
  • 16
  • 36