contract.set is not a function

2.5k views Asked by At

I am learning Ethereum development, I downloaded the react truffle suit and then tried to change some code to insert a string into the blockchain and then echo it. But I have an error which says: Unhandled Rejection (TypeError): contract.set is not a function

App.js:

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

import "./App.css";

class App extends Component {
  state = { storageValue: "", web3: null, accounts: null, contract: null, newValue: "" };

  componentDidMount = async () => {
    try {
      this.handleChange = this.handleChange.bind(this);
      this.handleSubmit = this.handleSubmit.bind(this);
      // 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 = SimpleStorageContract.networks[networkId];
      const instance = new web3.eth.Contract(
        SimpleStorageContract.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({ web3, accounts, contract: instance }, this.runExample);
    } 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);
    }
  };

  handleChange(event) {
    this.setState({newValue: event.target.value });
  }

  async handleSubmit(event) {
    event.preventDefault();

    const { accounts, contract } = this.state;
    await contract.set(this.state.newValue, {from: accounts[0]});
    const response = await contract.get();
    this.setState({storageValue: response });
  }

  runExample = async () => {
    const { contract } = this.state;

    // Get the value from the contract to prove it worked.
    const response = await contract.methods.get().call();

    // Update state with the result.
    this.setState({ storageValue: response });
  };

  render() {
    if (!this.state.web3) {
      return <div>Loading Web3, accounts, and contract...</div>;
    }
    return (
      <div className="App">
        <h1>Sample</h1>
        <div>Text: {this.state.storageValue}</div>
        <form onSubmit={this.handleSubmit}>
          <input type="text" value={this.state.newValue} onChange={this.handleChange.bind(this)}></input>
          <input type="submit" value="Submit"></input>
        </form>
      </div>
    );
  }
}

export default App;

Here is the contract which the set function is declared:

SimpleStorage.sol:

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.21 <0.7.0;

contract SimpleStorage {
    string storedData;

    constructor(string memory x) public {
      storedData = x;
    }

    function set(string memory x) public {
        storedData = x;
    }

    function get() public view returns (string memory) {
        return storedData;
    }
}
1

There are 1 answers

0
Petr Hejda On

This line in your code uses syntax of the Truffle package:

await contract.set(this.state.newValue, {from: accounts[0]});

But your code only imports web3js (not Truffle) and seems to be using it correctly in other places.

In web3js, you need to use the methods property (same as you're using in contract.methods.get()) of the contract object. As well as the send() function (that accepts the object with the from property) to send a transaction instead of a call.

So it should be

await contract.methods.set(this.state.newValue).send({from: accounts[0]});

Note: Web3js and Truffle are two separate packages, not related to each other. But both can be used to interact with smart contracts.