Search code examples
reactjsreact-hooksethereumuse-effectweb3js

how do I automatically display the connected wallet address on the website without needing to refresh the page


enter image description here

I have a simple website with nothing but the connected wallet address as shown.

Now my issue is that if I switch to a different connected wallet on my Metamask, the address shown on the UI doesn't change. It's similar to how pancakeswap.finance is able to show ur new connected wallet address on the connected wallet button immediately after you connect and switch accounts.

Here is my React code:

import React, { useEffect, useState } from "react";
import { ethers } from "ethers";
import "./App.css";

const App = () =>{
  const [currentAccount, setCurrentAccount] = useState("");
  const [userAddress, setUserAddress] = useState("");

  const detailsOn = async () =>{
    const { ethereum } = window;
    const provider = new ethers.providers.Web3Provider(ethereum);
    const signer = provider.getSigner();
    
    const addr = await signer.getAddress();

    setUserAddress(addr.toString());
  }

  const checkIfWalletIsConnected = async () =>{
    try{
      const { ethereum } = window;

      if(!ethereum){
        console.log("Use Metamask!");
      } else{
        console.log("Ethereum object found", ethereum);
        detailsOn();
      }

      const accounts = await ethereum.request({method: 'eth_accounts'});

      if(accounts !== 0){
        const account = accounts[0];
        console.log("Found an authorized account ", account);
        setCurrentAccount(account);
        detailsOn();
      } else{
        console.log("Could not find an authorized account");
      }
    } catch(error){
      console.log(error);
    }
  }

  const connectWallet = async () =>{
    try{
      const { ethereum } = window;

      if(!ethereum){
        alert("Use Metamask!");
      } else{
        const accounts = await ethereum.request({ method: 'eth_requestAccounts'});
        console.log("Account connected ", accounts[0]);

        setCurrentAccount(accounts[0]);
      }
    } catch(error){
      console.log(error);
    }
  }

  useEffect( () =>{

    checkIfWalletIsConnected();
  }, []);

  return (
    <div className="mainContainer">
      <div className="dataContainer">

        <div className="bio">
        Account: {userAddress}
        </div>
        
        {!currentAccount && (
          <button className="generalButton" onClick={connectWallet}>
          Connect Wallet
          </button>
        )}
      </div>
    </div>
  );
}

export default App;

I added the following so that the UI will update automatically when the user changes his wallet without needing to refresh the page.

  useEffect( () =>{
    const onNewSigner = async () =>{
      let addr;
      if(window.ethereum){
        const provider = new ethers.providers.Web3Provider(window.ethereum);
        const signer = provider.getSigner();

        addr = await signer.getAddress();

        setUserAddress(addr.toString());
      }
    }

    onNewSigner();
  }, []);

but it didn't do anything.


Solution

  • From the MetaMask docs

    window.ethereum.on('accountsChanged', function (accounts) {
      // Time to reload your interface with accounts[0]!
    })
    
    window.ethereum.on('networkChanged', function (networkId) {
      // Time to reload your interface with the new networkId
    })
    

    You need to make sure you handle the accountsChanged properly when metamask makes a change. In order to that

    window.ethereum.on('accountsChanged', function () {
     detailsOn();
    })