Truffle with React

11/02/2018
11/02/2018 erbileren
The estimated reading time for this post is 5 minutes

In previous posts, we created a react app (Part 1) then added webpack to the project (Part 2). Now, it is the time for starting with a Truffle project.

For those who have not heard about Truffle before, here is the official website: Truffle Framework

First, install Truffle globally:

npm install -g truffle

Then, inside the project root initialize Truffle:

cd react-app-scratch
truffle init

With the end of the truffle initialization, the project folder structure should be like this:

-- contracts/
-- migrations/
-- src/
-- webpack/
-- index.css
-- index.html
-- index.js
-- package.json
-- truffle-config.js
-- truffle.js

We will use truffle-contract (GitHub Page) for Ethereum contract abstraction and truffle-solidity-loader (GitHub Page) to access the truffle config file in the project.

npm install -save truffle-contract
npm install -save-dev truffle-solidity-loader

After the installation of packages, we need to specify solidity loader in the webpack file by adding these lines in loaders:

...,
{
  test: /\.sol/,
  exclude: /node_modules/,
  loader: 'truffle-solidity'
}

Let’s start with contracts…

A smart contract is a computer protocol intended to digitally facilitate, verify, or enforce the negotiation or performance of a contract. Smart contracts allow the performance of credible transactions without third parties.

Source: https://en.wikipedia.org/wiki/Smart_contract

In the contracts folder there is a Migrations.sol file, which helps keep track migrations, comes by default. In the same folder, create a new file SimpleContract.sol.

touch SimpleContract.sol

Our smart contract will be a very simple contract. It has one variable, simpleData, and its get and set functions:

pragma solidity ^0.4.18;

contract SimpleContract {
  uint simpleData;

  function setData(uint x) public {
    simpleData = x;
  }

  function getData() public view returns (uint) {
    return simpleData;
  }
}

The next step is creating migration file that is used by truffle migration later. In the migrations folder, create a new file. The important thing is the file name. You need to specify the migration order by file names. Since there is a 1_initial_migration.js file in the folder, we create the new file starting with 2_.

touch 2_deploy_contracts.js

In the migration file, we need to specify which contract(s) will be migrated. We have only one contract which is SimpleContract.sol so our migration file should be like in the following:

var SimpleContract = artifacts.require("./SimpleContract.sol");

module.exports = function(deployer) {
  deployer.deploy(SimpleContract);
};

The next step is editing truffle configuration files. By default, these files created empty and we should specify the how truffle works. If you are using Windows machine you need a different config file called truffle-config.js. My suggestion is creating both two configuration files with the same information to be able to work independently from the operating system.

Here is how truffle configuration file should look like:

module.exports = {
  // the path where migration files located
  migrations_directory: './migrations',
  networks: {
    // since we are using localhost for development, we use these parameters:
    development: {
      host: "127.0.0.1",
      port: 7545,
      network_id: "*"
    }
  }
};

After all these configurations about truffle, let’s compile our smart contract

truffle compile

If you see this output on your console screen, it means compiling finished without any errors. If you don’t check your code and try to compile again.

Compiling .\contracts\Migrations.sol...
Compiling .\contracts\SimpleContract.sol...
Writing artifacts to .\build\contracts

And we can start coding for the sample project. We will store our code in the src path. First, create a utils file in src path to store helper classes.

cd src
mkdir utils

To create a web3 connection, we use helper, getWeb3…

touch getWeb3.js

After create the file, add the following code into getWeb3.js

import Web3 from "web3";

let getWeb3 = new Promise(function(resolve, reject) {
  // waits for windows loading to chech web3 connection
  window.addEventListener("load", function() {
    var results;
    var web3 = window.web3;

    // first, check if there is a web3 connection if not, set the provider
    if (typeof web3 !== "undefined") {
      web3 = new Web3(web3.currentProvider);

      results = {
        web3: web3
      };

      console.log("Injected web3 detected.");

      resolve(results);
    } else {
      var provider = new Web3.providers.HttpProvider("localhost:8545");

      web3 = new Web3(provider);

      results = {
        web3: web3
      };

      console.log("No web3 instance injected, using Local web3.");

      resolve(results);
    }
  });
});

export default getWeb3;

The second helper is instantiateContracts. I prefer storing web3 related code seperated from the main react code.

touch instantiateContracts.js

This is our instantiateContracts class:

// we use compiled SimpleContact file
import SimpleContract from '../../build/contracts/SimpleContract.json'
import getWeb3 from './getWeb3'

import contract from 'truffle-contract'

class instantiateContract {
    web3 = {}

    static setWeb3() {
        getWeb3.then(results => {
            this.web3 = results.web3
        }).catch(() => {
            console.log('Error finding web3.')
        })
    }

    // call setData function int he contract
    static setValue(val) {
        var simpleContract = contract(SimpleContract)
        simpleContract.setProvider(this.web3.currentProvider)

        this.web3.eth.getAccounts((error, accounts) => {
            simpleContract.deployed().then((instance) => {
                // sets the given value to the contract
                return instance.setData(val, { from: accounts[0] })
            }).catch((error) => {
                console.error(error);
            })
        })
    }

    // call getData function int he contract
    static getValue() {
        return new Promise((resolve, reject) => {
            var simpleContract = contract(SimpleContract)
            simpleContract.setProvider(this.web3.currentProvider)

            this.web3.eth.getAccounts((error, accounts) => {
                simpleContract.deployed().then((instance) => {
                    // Get the value from the contract
                    return instance.getData.call({ from: accounts[0] })
                }).then((result) => {
                    // Resolve the result
                    resolve(result.c[0])
                }).catch((error) => {
                    console.error(error);
                })
            })
        })
    }
}
export default instantiateContract

The final thing is creating the react component. In the src path, there is a App.js file generated previously. Let’s edit this for testing the smart contract:

import React, { Component } from 'react'
import instantiateContract from './utils/instantiateContract'

class App extends Component {
    constructor(props) {
        super(props)

        // dataValue is the value given from user as input, valueFromChain is the stored value in the chain
        this.state = {
            dataValue: 0,
            valueFromChain: 0
        }
    }

    componentWillMount() {
        instantiateContract.setWeb3()
    }

    handleChange(e) {
        e.preventDefault()

        this.setState({ dataValue: e.target.value })
    }

    handleClick(e) {
        e.preventDefault()

        instantiateContract.setValue(this.state.dataValue)
    }

    handleSecondClick(e) {
        e.preventDefault()

        instantiateContract.getValue().then((result) => {
            this.setState({
                valueFromChain: result
            })
        })
    }

    render() {
        return (
            <div className="App">
                <h2>Smart Contract Example Is Working!</h2>
                <input type="number" onChange={this.handleChange.bind(this)} />
                <button type="submit" onClick={this.handleClick.bind(this)}>Update value</button>
                <button type="submit" onClick={this.handleSecondClick.bind(this)}>Get value</button>
                <p>The value is: {this.state.valueFromChain}</p>
            </div>
        );
    }
}

export default App

For this part, the source file is in GitHub: https://github.com/erbileren/react-app-scratch/tree/master/part3-truffle

In the next part, I will explain how you can run this project on a private network using Metamask on your web browser…

, , , , ,

Comment (1)

  1. Ange Skin

    Thanks for one’s marvelous posting! I definitely enjoyed reading it, you are a great author.I will make certain to bookmark your blog and definitely will come back at some point.

Leave a Reply

Your email address will not be published. Required fields are marked *