0

I'm learning how to create web3 app with Metamask and react.js

I used create-react-app and follow https://github.com/ChainSafe/web3.js#troubleshooting-and-known-issues to solve errors around polyfill.

Then I followed https://docs.metamask.io/guide/onboarding-library.html#using-react to use Metamsk with react.

DOM does render as expected when metamask is not installed to a browser, but does NOT render when installed. It goes only <div id='root></div> in body tag.

Why does not rendered only when Metamask is installed? Any idea?

App.js is

import React from 'react';
import './App.css';
import Header from './components/Header/Header';
import Main from './components/Main/Main';
import Description from './components/Description/Description';

const App = () => {
  
  return (
    <div>
      <Header />
      <Main />
      <Description />
    </div>
  )
}

export default App

Main.jsx

import './main.css';
import React, { useState, useEffect, useRef } from 'react'
import Web3 from 'web3';
import OnboardingButton from './OnboardingButton'

const Main = () => {
  return (
    <div className="container container__main">
        <OnboardingButton />
    </div>
  )
}

export default Main

OnboardingButton.jsx

import React, { useState, useEffect, useRef } from 'react'
import MetaMaskOnboarding from '@metamask/onboarding';

const ONBOARD_TEXT = 'Click here to install Metamask.'
const CONNECT_TEXT = 'Connect';
const CONNECTED_TEXT = 'Connected';


const OnboardingButton = () => {

    const [buttonText, setButtonText] = useState(ONBOARD_TEXT);
    const [isDisabled, setDisabled] = useState(false);
    const [accounts, setAccounts] = useState([]);
    const onboarding = useRef();


    // execute only when DOM initialized
    useEffect(() => {
        if (!onboarding.current) {
            onboarding.current = new MetaMaskOnboarding();
        }
    }, []);

    useEffect(() => {
        if (MetaMaskOnboarding.isMetaMaskInstalled()) {
            if (accounts.length > 0) {
                setButtonText(CONNECTED_TEXT);
                setDisabled(true);
                onboarding.current.stopOnboarding();
            } else {
                setButtonText(CONNECT_TEXT);
                setDisabled(false);
            }
        }
    }, [accounts]);

    useEffect(() => {
        function handleNewAccounts(newAccounts) {
            setAccounts(newAccounts);
        }
        if (MetaMaskOnboarding.isMetaMaskInstalled()) {
            window.ethereum.on('accountsChanged', handleNewAccounts);
            return () => {
                window.ethereum.off('accountsChanged', handleNewAccounts);
            };
        }
    }, []);

    const onClick = () => {
        if (MetaMaskOnboarding.isMetaMaskInstalled()) {
            window.ethereum
                .request({ method: 'eth_requestAccounts' })
                .then((newAccounts) => setAccounts(newAccounts));
        } else {
            onboarding.current.startOnboarding();
        }
    };
    
  
    return (
        <button disabled={isDisabled} onClick={onClick}>
            {buttonText}
        </button>
    );
}

export default OnboardingButton

package.json dependencies

  "dependencies": {
    "@metamask/onboarding": "^1.0.1",
    "@testing-library/jest-dom": "^5.16.4",
    "@testing-library/react": "^13.3.0",
    "@testing-library/user-event": "^13.5.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-scripts": "5.0.1",
    "web-vitals": "^2.1.4",
    "web3": "^1.7.4"
    }
TylerH
  • 20,799
  • 66
  • 75
  • 101
n Z
  • 1

1 Answers1

0

Firstly, I noticed I skipped copying this code into 3rd useEffect() according to Metamask's Tutorial but this was not a solution.

window.ethereum
  .request({ method: 'eth_requestAccounts' })
  .then((newAccounts) => setAccounts(newAccounts));

And I deleted the 3rd useEffect() that request connecting Metamask when initialized, somehow rendered successfully. Individually I think webapp should not request connecting to a wallet when a website just opened so I don't need the 3rd useEffect from Metamask's tutorial.

n Z
  • 1