[Ethereum] Cannot read property ‘eth’ of undefined

go-ethereumreactsolidity

I want to Interact with my Smart Contract via Web3 and React. But I get a error message with the following code.

    import React, { Component } from 'react';
    import Web3 from 'web3';

    let web3;
    if (typeof window !== 'undefined' && typeof window.web3 !== 'undefined') {
    // We are in the browser and metamask is running.

    web3 = new Web3(window.web3.currentProvider);
    console.log('ok');
    } else {



       // We are on the server Or the user is not running metamask
        //  Not relavant yet
        console.log('Problem?');

    }
 console.log(web3);

const abi = [ { "constant": true, "inputs": [ { "name": "", "type": "uint256" } ], "name": "deployedCampaigns", "outputs": [ { "name": "", "type": "address", "value": "0x561C3ec9fb72C0010dc6206546578C7dD8D9B0dA" } ], "payable": false, "stateMutability": "view", "type": "function", "signature": "0x339d50a5" }, { "constant": false, "inputs": [ { "name": "minimum", "type": "uint256" } ], "name": "createCampagn", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function", "signature": "0x3bcf3e08" }, { "constant": true, "inputs": [], "name": "getDeployedCampaigns", "outputs": [ { "name": "", "type": "address[]", "value": [ "0x561C3ec9fb72C0010dc6206546578C7dD8D9B0dA" ] } ], "payable": false, "stateMutability": "view", "type": "function", "signature": "0x4acb9d4f" } ];
const instance = new web3.eth.Contract(
    abi,
    '0x230e5d3b76EE412579BfD0e656a2158EC09edaB0'
);

console.log(instance);


class CampaignIndex extends Component {

    async  componentDidMount(){

        const campaigns = instance.methods.getDeployedCampaigns().call();
        console.log(campaigns);

    }

    render( ) {
        return (
            <div>Campaigns Index</div>
        );
    }
}

export default CampaignIndex;

The error message is the following:

enter image description here

It seems the code line

 new web3.eth.Contract

throws the error message. But when I look into the console log(instance) I get the Web3 instance. So I have no idea what the problem could be.

This are my Package Configurations:

 {
  "name": "kickstarter2",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "next dev"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "fs-extra": "^7.0.0",
    "ganache-cli": "^6.1.8",
    "mocha": "^5.2.0",
    "next": "^4.2.3",
    "react": "^16.6.0",
    "react-dom": "^16.6.0",
    "solc": "^0.4.25",
    "web3": "^1.0.0-beta.35"
  }
}

Does anyone have the solution to this problem?

Best Answer

There's a javascript issue in your code: you're using both the web3 injected by metamask (window.web3), and the web3 you're declaring (let web3;). They are both declared in the same scope and that can create subtle issues.

Have a look at below scenario, which is similar to your code and see if it's obvious what's going on:

> window.aaa = 100;
< 100

> aaa
< 100

> let aaa = 200
< undefined

> aaa
< 200

> window.aaa
< 100

I'd suggest you to use a variable named differently for your instance of Web3, let's say web3js:

    import React, { Component } from 'react';
    import Web3 from 'web3';

    let web3js;
    if (typeof window !== 'undefined' && typeof window.web3 !== 'undefined') {
    // We are in the browser and metamask is running.

    web3js = new Web3(window.web3.currentProvider);
    console.log('ok');
    } else {



       // We are on the server Or the user is not running metamask
        //  Not relavant yet
        console.log('Problem?');

    }
 console.log('WEB3JS: ',web3js);

const abi = [ { "constant": true, "inputs": [ { "name": "", "type": "uint256" } ], "name": "deployedCampaigns", "outputs": [ { "name": "", "type": "address", "value": "0x561C3ec9fb72C0010dc6206546578C7dD8D9B0dA" } ], "payable": false, "stateMutability": "view", "type": "function", "signature": "0x339d50a5" }, { "constant": false, "inputs": [ { "name": "minimum", "type": "uint256" } ], "name": "createCampagn", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function", "signature": "0x3bcf3e08" }, { "constant": true, "inputs": [], "name": "getDeployedCampaigns", "outputs": [ { "name": "", "type": "address[]", "value": [ "0x561C3ec9fb72C0010dc6206546578C7dD8D9B0dA" ] } ], "payable": false, "stateMutability": "view", "type": "function", "signature": "0x4acb9d4f" } ];
const instance = new web3js.eth.Contract(
    abi,
    '0x230e5d3b76EE412579BfD0e656a2158EC09edaB0'
);

console.log(instance);


class CampaignIndex extends Component {

    async  componentDidMount(){

        const campaigns = instance.methods.getDeployedCampaigns().call();
        console.log(campaigns);

    }

    render( ) {
        return (
            <div>Campaigns Index</div>
        );
    }
}

export default CampaignIndex;

Also, please note that starting today, 2nd of November 2018, a breaking change was introduced by metamask. It doesn't seem to affect your usage of web3 (since you don't access the accounts used), but their recommended way to instantiate Web3 is:

window.addEventListener('load', async () => {
    // Modern dapp browsers...
    if (window.ethereum) {
        window.web3 = new Web3(ethereum);
        try {
            // Request account access if needed
            await ethereum.enable();
            // Acccounts now exposed
            web3.eth.sendTransaction({/* ... */});
        } catch (error) {
            // User denied account access...
        }
    }
    // Legacy dapp browsers...
    else if (window.web3) {
        window.web3 = new Web3(web3.currentProvider);
        // Acccounts always exposed
        web3.eth.sendTransaction({/* ... */});
    }
    // Non-dapp browsers...
    else {
        console.log('Non-Ethereum browser detected. You should consider trying MetaMask!');
    }
});

And since you're building *a new** app, it would be best to follow that guideline.