'Web3 error when trying to call contract methods

I encounter the following error while trying to run a dapp made using React, Truffle & Ganache. I'm also using web3 version 1.7.1. The problem is that the code enters in a catch(error) sequence of a try/catch and then displays what it is intended correctly. Why is this happening and why does the following error appears?

index.js:1 TypeError: Cannot read properties of undefined (reading 'methods')
at HomePage.componentDidMount

What the code should do: Display something like "Address is: 0x0D05b3220E9cC7A90623fc506cEB64Ab885FD6C6"

What the code does: It shows me the prompt "Failed to load web3, accounts, or contract. Check console for details" AND THEN "Address is: 0x0D05b3220E9cC7A90623fc506cEB64Ab885FD6C6"

The code is the following:

import React, { Component } from "react";
import MySmartContract from "../contracts/MySmartContract.json";
import getWeb3 from "../getWeb3";

//Importing components



class HomePage extends Component {
  constructor(props) {
    super(props);

    this.state = {
      ContractInstance: undefined,
      account: null,
      web3: null,
      isOwner: false
    }
  }

  componentDidMount = async () => {

    // For refreshing the page a single time
    // so that web3 and instance is loaded every time
    if (!window.location.hash) {
      window.location = window.location + '#loaded';
      window.location.reload();
    }

    try {
      // Get network provider and web3 instance.
      const web3 = await getWeb3();

      // Use web3 to get the user's accounts.
      const accounts = await web3.eth.getAccounts();

      // Get the contract instance.
      const networkId = await web3.eth.net.getId();
      const deployedNetwork = MySmartContract.networks[networkId];
      const instance = new web3.eth.Contract(
        MySmartContract.abi,
        deployedNetwork && deployedNetwork.address,
      );

      // Set web3, accounts, and contract to the state, and then proceed with an
      // example of interacting with the contract's methods.
      this.setState({ ContractInstance: instance, web3: web3, account: accounts[0] });


      const owner = await this.state.ContractInstance.methods.getOwnerAddress().call();
      if (this.state.account === owner) {
        this.setState({ isOwner: true });
      }

  

    } catch (error) {
      // Catch any errors for any of the above operations.
      alert(
        `Failed to load web3, accounts, or contract. Check console for details.`,
      );
      console.error(error);
    }
  };


  render() {


    if (!this.state.web3) {

      return (
       
            <h1>
              Loading Web3, accounts and contract...
            </h1>
          
         
     
      )

    }
    return (
      <div><h1>Address is: {this.state.account}</h1></div>

    )

  }
}

export default HomePage;

The content of getWeb3.js is the following:

import Web3 from "web3";

const getWeb3 = () =>
  new Promise((resolve, reject) => {
    // Wait for loading completion to avoid race conditions with web3 injection timing.
    window.addEventListener("load", async () => {
      // Modern dapp browsers...
      if (window.ethereum) {
        const web3 = new Web3(window.ethereum);
        try {
          // Request account access if needed
          await window.ethereum.enable();
          // Accounts now exposed
          resolve(web3);
        } catch (error) {
          reject(error);
        }
      }
      // Legacy dapp browsers...
      else if (window.web3) {
        // Use Mist/MetaMask's provider.
        const web3 = window.web3;
        console.log("Injected web3 detected.");
        resolve(web3);
      }
      // Fallback to localhost; use dev console port by default...
      else {
        const provider = new Web3.providers.HttpProvider(
          "http://127.0.0.1:8545"
        );
        const web3 = new Web3(provider);
        console.log("No web3 instance injected, using Local web3.");
        resolve(web3);
      }
    });
  });

export default getWeb3;


Solution 1:[1]

This code seems to be wrong!

this.setState({ ContractInstance: instance, web3: web3, account: accounts[0] });


const owner = await this.state.ContractInstance.methods.getOwnerAddress().call();
      

You should not try to use state value as soon as you set up.

So you need to call your function in the second line like this:

const owner = await instance.methods.getOwnerAddress().call();

Injected connector code sample

const ConnectToInjected = async () => {
  let provider = null;
  if (typeof window.ethereum !== 'undefined') {
    provider = window.ethereum;
    try {
      await provider.request({ method: 'eth_requestAccounts' })
    } catch (error) {
      throw new Error("User Rejected");
    }
  } else if (window.web3) {
    provider = window.web3.currentProvider;
  } else if (window.celo) {
    provider = window.celo;
  } else {
    throw new Error("No Web3 Provider found");
  }
  return provider;
};

export default ConnectToInjected;

Usage:

const provider = await ConnectToInjected();
// Open metamask
await provider.request({ method: 'eth_requestAccounts' });
const web3 = new Web3(provider)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1